microsoft/vscode-react-native

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
e67ace8aab1da5ee01f5a9eec52e406501d301e4

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/debugger/direct/directDebugAdapter.ts

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