microsoft/vscode-react-native

Public

mirrored from https://github.com/microsoft/vscode-react-nativeAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
3c6708ad91fa1479dbb417251dc86d4fc0d34b00

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/debugger/direct/directDebugAdapter.ts

207lines · 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.getReactNativeVersions(launchArgs.cwd, launchArgs.platform === "windows")
75 .then(versions => {
76 extProps = TelemetryHelper.addPropertyToTelemetryProperties(versions.reactNativeVersion, "reactNativeVersion", extProps);
77 if (launchArgs.platform === "windows") {
78 extProps = TelemetryHelper.addPropertyToTelemetryProperties(versions.reactNativeWindowsVersion, "reactNativeWindowsVersion", extProps);
79 }
80 return TelemetryHelper.generate("launch", extProps, (generator) => {
81 return this.remoteExtension.launch({ "arguments": launchArgs })
82 .then(() => {
83 return this.remoteExtension.getPackagerPort(launchArgs.cwd);
84 })
85 .then((packagerPort: number) => {
86 launchArgs.port = launchArgs.port || packagerPort;
87 this.attach(launchArgs).then(() => {
88 resolve();
89 }).catch((e) => reject(e));
90 }).catch((e) => reject(e));
91 })
92 .catch((err) => {
93 this.outputLogger("An error occurred while launching the application. " + err.message || err, true);
94 this.cleanUp();
95 reject(err);
96 });
97 });
98 }));
99 }
100
101 public attach(attachArgs: IDirectAttachRequestArgs): Promise<void> {
102 let extProps = {
103 platform: {
104 value: attachArgs.platform,
105 isPii: false,
106 },
107 isDirect: {
108 value: true,
109 isPii: false,
110 },
111 };
112
113 this.previousAttachArgs = attachArgs;
114
115 return new Promise<void>((resolve, reject) => this.initializeSettings(attachArgs)
116 .then(() => {
117 this.outputLogger("Attaching to the application");
118 logger.verbose(`Attaching to the application: ${JSON.stringify(attachArgs, null , 2)}`);
119 return ReactNativeProjectHelper.getReactNativeVersions(attachArgs.cwd, true)
120 .then(versions => {
121 extProps = TelemetryHelper.addPropertyToTelemetryProperties(versions.reactNativeVersion, "reactNativeVersion", extProps);
122 if (versions.reactNativeWindowsVersion) {
123 extProps = TelemetryHelper.addPropertyToTelemetryProperties(versions.reactNativeWindowsVersion, "reactNativeWindowsVersion", extProps);
124 }
125 return TelemetryHelper.generate("attach", extProps, (generator) => {
126 return this.remoteExtension.getPackagerPort(attachArgs.cwd)
127 .then((packagerPort: number) => {
128 attachArgs.port = attachArgs.port || packagerPort;
129 this.outputLogger(`Connecting to ${attachArgs.port} port`);
130 const attachArguments = Object.assign({}, attachArgs, {
131 address: "localhost",
132 port: attachArgs.port,
133 restart: true,
134 request: "attach",
135 remoteRoot: undefined,
136 localRoot: undefined,
137 });
138 super.attach(attachArguments).then(() => {
139 this.outputLogger("The debugger attached successfully");
140 resolve();
141 }).catch((e) => reject(e));
142 }).catch((e) => reject(e));
143 })
144 .catch((err) => {
145 this.outputLogger("An error occurred while attaching to the debugger. " + err.message || err, true);
146 this.cleanUp();
147 reject(err);
148 });
149 });
150 }));
151 }
152
153 public disconnect(args: DebugProtocol.DisconnectArguments): void {
154 this.cleanUp();
155 super.disconnect(args);
156 }
157
158 private initializeSettings(args: any): Q.Promise<any> {
159 if (!this.isSettingsInitialized) {
160 let chromeDebugCoreLogs = getLoggingDirectory();
161 if (chromeDebugCoreLogs) {
162 chromeDebugCoreLogs = path.join(chromeDebugCoreLogs, "ChromeDebugCoreLogs.txt");
163 }
164 let logLevel: string = args.trace;
165 if (logLevel) {
166 logLevel = logLevel.replace(logLevel[0], logLevel[0].toUpperCase());
167 logger.setup(Logger.LogLevel[logLevel], chromeDebugCoreLogs || false);
168 } else {
169 logger.setup(Logger.LogLevel.Log, chromeDebugCoreLogs || false);
170 }
171
172 if (!args.sourceMaps) {
173 args.sourceMaps = true;
174 }
175
176 const projectRootPath = getProjectRoot(args);
177 return ReactNativeProjectHelper.isReactNativeProject(projectRootPath)
178 .then((result) => {
179 if (!result) {
180 throw ErrorHelper.getInternalError(InternalErrorCode.NotInReactNativeFolderError);
181 }
182 this.projectRootPath = projectRootPath;
183 this.remoteExtension = RemoteExtension.atProjectRootPath(this.projectRootPath);
184 const version = getExtensionVersion();
185
186 // Start to send telemetry
187 (this._session as any).getTelemetryReporter().reassignTo(new RemoteTelemetryReporter(
188 "react-native-tools", version, Telemetry.APPINSIGHTS_INSTRUMENTATIONKEY, this.projectRootPath));
189
190 this.isSettingsInitialized = true;
191
192 return void 0;
193 });
194 } else {
195 return Q.resolve<void>(void 0);
196 }
197 }
198
199 private cleanUp() {
200 if (this.previousAttachArgs.platform === "android") {
201 this.remoteExtension.stopMonitoringLogcat()
202 .catch(reason => logger.warn(localize("CouldNotStopMonitoringLogcat", "Couldn't stop monitoring logcat: {0}", reason.message || reason)))
203 .finally(() => super.disconnect({terminateDebuggee: true}));
204 }
205 }
206
207}