Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

coreclr-debug nullability #5405

Merged
33 changes: 13 additions & 20 deletions src/coreclr-debug/ParsedEnvironmentFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import * as fs from 'fs-extra';
import * as fs from 'fs';

export class ParsedEnvironmentFile {
public Env: { [key: string]: any };
public Warning: string | null;
public Warning: string | undefined;

private constructor(env: { [key: string]: any }, warning: string | null) {
private constructor(env: { [key: string]: any }, warning: string | undefined) {
this.Env = env;
this.Warning = warning;
}
Expand All @@ -20,26 +20,22 @@ export class ParsedEnvironmentFile {
}

public static CreateFromContent(content: string, envFile: string, initialEnv: { [key: string]: any } | undefined): ParsedEnvironmentFile {

// Remove UTF-8 BOM if present
if (content.charAt(0) === '\uFEFF') {
content = content.substr(1);
content = content.substring(1);
}

let parseErrors: string[] = [];
let env: { [key: string]: any } = initialEnv;
if (!env) {
env = {};
}
let env = initialEnv ?? {};

content.split("\n").forEach(line => {
// Split the line between key and value
const r: RegExpMatchArray = line.match(/^\s*([\w\.\-]+)\s*=\s*(.*)?\s*$/);
const match = line.match(/^\s*([\w\.\-]+)\s*=\s*(.*)?\s*$/);

if (r !== null) {
const key: string = r[1];
let value: string = r[2] || "";
if ((value.length > 0) && (value.charAt(0) === '"') && (value.charAt(value.length - 1) === '"')) {
if (match !== null) {
const key = match[1];
let value = match[2] ?? "";
if (value.length > 0 && value.charAt(0) === '"' && value.charAt(value.length - 1) === '"') {
value = value.replace(/\\n/gm, "\n");
}

Expand All @@ -57,14 +53,11 @@ export class ParsedEnvironmentFile {
});

// show error message if single lines cannot get parsed
let warning: string = null;
let warning: string | undefined;
if (parseErrors.length !== 0) {
warning = "Ignoring non-parseable lines in envFile " + envFile + ": ";
parseErrors.forEach(function (value, idx, array) {
warning += "\"" + value + "\"" + ((idx !== array.length - 1) ? ", " : ".");
});
warning = `Ignoring non-parseable lines in envFile ${envFile}: ${parseErrors.join(", ")}.`;
}

return new ParsedEnvironmentFile(env, warning);
}
}
}
72 changes: 35 additions & 37 deletions src/coreclr-debug/activate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,26 @@ import { DebuggerPrerequisiteWarning, DebuggerPrerequisiteFailure, DebuggerNotIn
import { EventStream } from '../EventStream';
import CSharpExtensionExports from '../CSharpExtensionExports';
import { getRuntimeDependencyPackageWithId } from '../tools/RuntimeDependencyPackageUtils';
import { getDotnetInfo, DotnetInfo } from '../utils/getDotnetInfo';
import { getDotnetInfo } from '../utils/getDotnetInfo';
import { DotnetDebugConfigurationProvider } from './debugConfigurationProvider';
import { Options } from '../omnisharp/options';

let _debugUtil: CoreClrDebugUtil = null;

export async function activate(thisExtension: vscode.Extension<CSharpExtensionExports>, context: vscode.ExtensionContext, platformInformation: PlatformInformation, eventStream: EventStream, options: Options) {
_debugUtil = new CoreClrDebugUtil(context.extensionPath);
const debugUtil = new CoreClrDebugUtil(context.extensionPath);

if (!CoreClrDebugUtil.existsSync(_debugUtil.debugAdapterDir())) {
if (!CoreClrDebugUtil.existsSync(debugUtil.debugAdapterDir())) {
let isValidArchitecture: boolean = await checkIsValidArchitecture(platformInformation, eventStream);
// If this is a valid architecture, we should have had a debugger, so warn if we didn't, otherwise
// a warning was already issued, so do nothing.
if (isValidArchitecture) {
eventStream.post(new DebuggerPrerequisiteFailure("[ERROR]: C# Extension failed to install the debugger package."));
showInstallErrorMessage(eventStream);
}
} else if (!CoreClrDebugUtil.existsSync(_debugUtil.installCompleteFilePath())) {
completeDebuggerInstall(platformInformation, eventStream, options);
} else if (!CoreClrDebugUtil.existsSync(debugUtil.installCompleteFilePath())) {
completeDebuggerInstall(debugUtil, platformInformation, eventStream, options);
}

const factory = new DebugAdapterExecutableFactory(platformInformation, eventStream, thisExtension.packageJSON, thisExtension.extensionPath, options);
const factory = new DebugAdapterExecutableFactory(debugUtil, platformInformation, eventStream, thisExtension.packageJSON, thisExtension.extensionPath, options);
context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('coreclr', new DotnetDebugConfigurationProvider(platformInformation)));
context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('clr', new DotnetDebugConfigurationProvider(platformInformation)));
context.subscriptions.push(vscode.debug.registerDebugAdapterDescriptorFactory('coreclr', factory));
Expand Down Expand Up @@ -74,30 +72,29 @@ async function checkIsValidArchitecture(platformInformation: PlatformInformation
return false;
}

async function completeDebuggerInstall(platformInformation: PlatformInformation, eventStream: EventStream, options: Options): Promise<boolean> {
return _debugUtil.checkDotNetCli(options.dotNetCliPaths)
.then(async (dotnetInfo: DotnetInfo) => {
async function completeDebuggerInstall(debugUtil: CoreClrDebugUtil, platformInformation: PlatformInformation, eventStream: EventStream, options: Options): Promise<boolean> {
try {
await debugUtil.checkDotNetCli(options.dotNetCliPaths);
const isValidArchitecture = await checkIsValidArchitecture(platformInformation, eventStream);
if (!isValidArchitecture) {
eventStream.post(new DebuggerNotInstalledFailure());
vscode.window.showErrorMessage('Failed to complete the installation of the C# extension. Please see the error in the output window below.');
return false;
}

let isValidArchitecture: boolean = await checkIsValidArchitecture(platformInformation, eventStream);
// Write install.complete
CoreClrDebugUtil.writeEmptyFile(debugUtil.installCompleteFilePath());

if (!isValidArchitecture) {
eventStream.post(new DebuggerNotInstalledFailure());
vscode.window.showErrorMessage('Failed to complete the installation of the C# extension. Please see the error in the output window below.');
return false;
}

// Write install.complete
CoreClrDebugUtil.writeEmptyFile(_debugUtil.installCompleteFilePath());
return true;
} catch (err) {
const error = err as Error;

return true;
}, (err) => {
// Check for dotnet tools failed. pop the UI
// err is a DotNetCliError but use defaults in the unexpected case that it's not
showDotnetToolsWarning(err.ErrorMessage || _debugUtil.defaultDotNetCliErrorMessage());
eventStream.post(new DebuggerPrerequisiteWarning(err.ErrorString || err));
// TODO: log telemetry?
return false;
});
// Check for dotnet tools failed. pop the UI
showDotnetToolsWarning(error.message);
eventStream.post(new DebuggerPrerequisiteWarning(error.message));
// TODO: log telemetry?
return false;
}
}

function showInstallErrorMessage(eventStream: EventStream) {
Expand Down Expand Up @@ -133,7 +130,7 @@ function showDotnetToolsWarning(message: string): void {
// Else it will launch the debug adapter
export class DebugAdapterExecutableFactory implements vscode.DebugAdapterDescriptorFactory {

constructor(private readonly platformInfo: PlatformInformation, private readonly eventStream: EventStream, private readonly packageJSON: any, private readonly extensionPath: string, private readonly options: Options) {
constructor(private readonly debugUtil: CoreClrDebugUtil, private readonly platformInfo: PlatformInformation, private readonly eventStream: EventStream, private readonly packageJSON: any, private readonly extensionPath: string, private readonly options: Options) {
}

async createDebugAdapterDescriptor(_session: vscode.DebugSession, executable: vscode.DebugAdapterExecutable | undefined): Promise<vscode.DebugAdapterDescriptor> {
Expand Down Expand Up @@ -161,8 +158,7 @@ export class DebugAdapterExecutableFactory implements vscode.DebugAdapterDescrip
}
// install.complete does not exist, check dotnetCLI to see if we can complete.
else if (!CoreClrDebugUtil.existsSync(util.installCompleteFilePath())) {
let success: boolean = await completeDebuggerInstall(this.platformInfo, this.eventStream, this.options);

let success = await completeDebuggerInstall(this.debugUtil, this.platformInfo, this.eventStream, this.options);
if (!success) {
this.eventStream.post(new DebuggerNotInstalledFailure());
throw new Error('Failed to complete the installation of the C# extension. Please see the error in the output window below.');
Expand All @@ -172,14 +168,16 @@ export class DebugAdapterExecutableFactory implements vscode.DebugAdapterDescrip

// debugger has finished installation, kick off our debugger process

// Check for targetArchitecture
let dotNetInfo = await getDotnetInfo(this.options.dotNetCliPaths);
const targetArchitecture: string = getTargetArchitecture(this.platformInfo, _session.configuration.targetArchitecture, dotNetInfo);

// use the executable specified in the package.json if it exists or determine it based on some other information (e.g. the session)
if (!executable) {
const dotNetInfo = await getDotnetInfo(this.options.dotNetCliPaths);
const targetArchitecture = getTargetArchitecture(this.platformInfo, _session.configuration.targetArchitecture, dotNetInfo);
const command = path.join(common.getExtensionPath(), ".debugger", targetArchitecture, "vsdbg-ui" + CoreClrDebugUtil.getPlatformExeExtension());
executable = new vscode.DebugAdapterExecutable(command, [], { env: { 'DOTNET_ROOT' : dotNetInfo.CliPath ? path.dirname(dotNetInfo.CliPath) : '' } });
executable = new vscode.DebugAdapterExecutable(command, [], {
env: {
DOTNET_ROOT: dotNetInfo.CliPath ? path.dirname(dotNetInfo.CliPath) : '',
}
});
}

// make VS Code launch the DA executable
Expand Down
14 changes: 7 additions & 7 deletions src/coreclr-debug/debugConfigurationProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { PlatformInformation } from '../platform';
export class DotnetDebugConfigurationProvider implements vscode.DebugConfigurationProvider {
constructor(public platformInformation: PlatformInformation) {}

public async resolveDebugConfigurationWithSubstitutedVariables(folder: vscode.WorkspaceFolder | undefined, debugConfiguration: vscode.DebugConfiguration, token?: vscode.CancellationToken): Promise<vscode.DebugConfiguration>
public async resolveDebugConfigurationWithSubstitutedVariables(folder: vscode.WorkspaceFolder | undefined, debugConfiguration: vscode.DebugConfiguration, token?: vscode.CancellationToken): Promise<vscode.DebugConfiguration | null | undefined>
{
if (!debugConfiguration)
{
Expand All @@ -21,7 +21,7 @@ export class DotnetDebugConfigurationProvider implements vscode.DebugConfigurati
// Process Id is empty, handle Attach to Process Dialog.
if (debugConfiguration.request === "attach" && !debugConfiguration.processId && !debugConfiguration.processName)
{
let process: AttachItem = undefined;
let process: AttachItem | undefined;
if (debugConfiguration.pipeTransport)
{
process = await RemoteAttachPicker.ShowAttachEntries(debugConfiguration, this.platformInformation);
Expand All @@ -33,15 +33,15 @@ export class DotnetDebugConfigurationProvider implements vscode.DebugConfigurati
process = await attacher.ShowAttachEntries();
}

if (process)
if (process !== undefined)
{
debugConfiguration.processId = process.id;

if (debugConfiguration.type == "coreclr" &&
this.platformInformation.isMacOS() &&
if (debugConfiguration.type == "coreclr" &&
this.platformInformation.isMacOS() &&
this.platformInformation.architecture == 'arm64')
{
// For Apple Silicon M1, it is possible that the process we are attaching to is being emulated as x86_64.
// For Apple Silicon M1, it is possible that the process we are attaching to is being emulated as x86_64.
// The process is emulated if it has process flags has P_TRANSLATED (0x20000).
if (process.flags & 0x20000)
{
Expand All @@ -62,4 +62,4 @@ export class DotnetDebugConfigurationProvider implements vscode.DebugConfigurati

return debugConfiguration;
}
}
}
Loading