microsoft/vscode-react-native

Public

mirrored fromhttps://github.com/microsoft/vscode-react-nativeAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
70cfd5650973cc6872aaae01ea2db7a924e6b67b

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

src/debugger/direct/directDebugAdapter.ts

201lines · modecode

1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for details.
3
4import * as path from "path";
5import { ReactNativeProjectHelper } from "../../common/reactNativeProjectHelper";
6import { ErrorHelper } from "../../common/error/errorHelper";
7import { getExtensionVersion } from "../../common/extensionHelper";
8import { ILaunchArgs } from "../../extension/launchArgs";
9import { getProjectRoot } from "../nodeDebugWrapper";
10import { Telemetry } from "../../common/telemetry";
11import { OutputEvent, Logger } from "vscode-debugadapter";
12import { TelemetryHelper } from "../../common/telemetryHelper";
13import { RemoteTelemetryReporter } from "../../common/telemetryReporters";
14import { ChromeDebugAdapter, ChromeDebugSession, IChromeDebugSessionOpts, IAttachRequestArgs, logger } from "vscode-chrome-debug-core";
15import { InternalErrorCode } from "../../common/error/internalErrorCode";
16import { RemoteExtension } from "../../common/remoteExtension";
17import { DebugProtocol } from "vscode-debugprotocol";
18import { getLoggingDirectory } from "../../extension/log/LogHelper";
19import * as nls from "vscode-nls";
20import * as Q from "q";
21const localize = nls.loadMessageBundle();
22
23export interface IDirectAttachRequestArgs extends IAttachRequestArgs, ILaunchArgs {
24 cwd: string; /* Automatically set by VS Code to the currently opened folder */
25}
26
27export interface IDirectLaunchRequestArgs extends DebugProtocol.LaunchRequestArguments, IDirectAttachRequestArgs { }
28
29export class DirectDebugAdapter extends ChromeDebugAdapter {
30
31 private outputLogger: (message: string, error?: boolean | string) => void;
32 private projectRootPath: string;
33 private remoteExtension: RemoteExtension;
34 private isSettingsInitialized: boolean; // used to prevent parameters reinitialization when attach is called from launch function
35 private previousAttachArgs: IDirectAttachRequestArgs;
36
37 public constructor(opts: IChromeDebugSessionOpts, debugSession: ChromeDebugSession) {
38 super(opts, debugSession);
39 this.outputLogger = (message: string, error?: boolean | string) => {
40 let category = "console";
41 if (error === true) {
42 category = "stderr";
43 }
44 if (typeof error === "string") {
45 category = error;
46 }
47
48 let newLine = "\n";
49 if (category === "stdout" || category === "stderr") {
50 newLine = "";
51 }
52 debugSession.sendEvent(new OutputEvent(message + newLine, category));
53 };
54
55 this.isSettingsInitialized = false;
56 }
57
58 public launch(launchArgs: IDirectLaunchRequestArgs): Promise<void> {
59 let extProps = {
60 platform: {
61 value: launchArgs.platform,
62 isPii: false,
63 },
64 isDirect: {
65 value: true,
66 isPii: false,
67 },
68 };
69
70 return new Promise<void>((resolve, reject) => this.initializeSettings(launchArgs)
71 .then(() => {
72 this.outputLogger("Launching the application");
73 logger.verbose(`Launching the application: ${JSON.stringify(launchArgs, null , 2)}`);
74 return ReactNativeProjectHelper.getReactNativeVersion(launchArgs.cwd)
75 .then(version => {
76 extProps = TelemetryHelper.addReactNativeVersionToEventProperties(version, extProps);
77 return TelemetryHelper.generate("launch", extProps, (generator) => {
78 return this.remoteExtension.launch({ "arguments": launchArgs })
79 .then(() => {
80 return this.remoteExtension.getPackagerPort(launchArgs.cwd);
81 })
82 .then((packagerPort: number) => {
83 launchArgs.port = launchArgs.port || packagerPort;
84 this.attach(launchArgs).then(() => {
85 resolve();
86 }).catch((e) => reject(e));
87 }).catch((e) => reject(e));
88 })
89 .catch((err) => {
90 this.outputLogger("An error occurred while launching the application. " + err.message || err, true);
91 this.cleanUp();
92 reject(err);
93 });
94 });
95 }));
96 }
97
98 public attach(attachArgs: IDirectAttachRequestArgs): Promise<void> {
99 let extProps = {
100 platform: {
101 value: attachArgs.platform,
102 isPii: false,
103 },
104 isDirect: {
105 value: true,
106 isPii: false,
107 },
108 };
109
110 this.previousAttachArgs = attachArgs;
111
112 return new Promise<void>((resolve, reject) => this.initializeSettings(attachArgs)
113 .then(() => {
114 this.outputLogger("Attaching to the application");
115 logger.verbose(`Attaching to the application: ${JSON.stringify(attachArgs, null , 2)}`);
116 return ReactNativeProjectHelper.getReactNativeVersion(attachArgs.cwd)
117 .then(version => {
118 extProps = TelemetryHelper.addReactNativeVersionToEventProperties(version, extProps);
119 return TelemetryHelper.generate("attach", extProps, (generator) => {
120 return this.remoteExtension.getPackagerPort(attachArgs.cwd)
121 .then((packagerPort: number) => {
122 attachArgs.port = attachArgs.port || packagerPort;
123 this.outputLogger(`Connecting to ${attachArgs.port} port`);
124 const attachArguments = Object.assign({}, attachArgs, {
125 address: "localhost",
126 port: attachArgs.port,
127 restart: true,
128 request: "attach",
129 remoteRoot: undefined,
130 localRoot: undefined,
131 });
132 super.attach(attachArguments).then(() => {
133 this.outputLogger("The debugger attached successfully");
134 resolve();
135 }).catch((e) => reject(e));
136 }).catch((e) => reject(e));
137 })
138 .catch((err) => {
139 this.outputLogger("An error occurred while attaching to the debugger. " + err.message || err, true);
140 this.cleanUp();
141 reject(err);
142 });
143 });
144 }));
145 }
146
147 public disconnect(args: DebugProtocol.DisconnectArguments): void {
148 this.cleanUp();
149 super.disconnect(args);
150 }
151
152 private initializeSettings(args: any): Q.Promise<any> {
153 if (!this.isSettingsInitialized) {
154 let chromeDebugCoreLogs = getLoggingDirectory();
155 if (chromeDebugCoreLogs) {
156 chromeDebugCoreLogs = path.join(chromeDebugCoreLogs, "ChromeDebugCoreLogs.txt");
157 }
158 let logLevel: string = args.trace;
159 if (logLevel) {
160 logLevel = logLevel.replace(logLevel[0], logLevel[0].toUpperCase());
161 logger.setup(Logger.LogLevel[logLevel], chromeDebugCoreLogs || false);
162 } else {
163 logger.setup(Logger.LogLevel.Log, chromeDebugCoreLogs || false);
164 }
165
166 if (!args.sourceMaps) {
167 args.sourceMaps = true;
168 }
169
170 const projectRootPath = getProjectRoot(args);
171 return ReactNativeProjectHelper.isReactNativeProject(projectRootPath)
172 .then((result) => {
173 if (!result) {
174 throw ErrorHelper.getInternalError(InternalErrorCode.NotInReactNativeFolderError);
175 }
176 this.projectRootPath = projectRootPath;
177 this.remoteExtension = RemoteExtension.atProjectRootPath(this.projectRootPath);
178 const version = getExtensionVersion();
179
180 // Start to send telemetry
181 (this._session as any).getTelemetryReporter().reassignTo(new RemoteTelemetryReporter(
182 "react-native-tools", version, Telemetry.APPINSIGHTS_INSTRUMENTATIONKEY, this.projectRootPath));
183
184 this.isSettingsInitialized = true;
185
186 return void 0;
187 });
188 } else {
189 return Q.resolve<void>(void 0);
190 }
191 }
192
193 private cleanUp() {
194 if (this.previousAttachArgs.platform === "android") {
195 this.remoteExtension.stopMonitoringLogcat()
196 .catch(reason => logger.warn(localize("CouldNotStopMonitoringLogcat", "Couldn't stop monitoring logcat: {0}", reason.message || reason)))
197 .finally(() => super.disconnect({terminateDebuggee: true}));
198 }
199 }
200
201}
202