Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"debugger"
],
"engines": {
"vscode": "^1.38.0"
"vscode": "^1.42.0"
},
"license": "SEE LICENSE IN LICENSE.txt",
"repository": {
Expand All @@ -35,6 +35,7 @@
"onDebugInitialConfigurations",
"onDebugResolve:java",
"onCommand:JavaDebug.SpecifyProgramArgs",
"onCommand:JavaDebug.PickJavaProcess",
"onCommand:java.debug.runJavaFile",
"onCommand:java.debug.debugJavaFile"
],
Expand Down Expand Up @@ -171,7 +172,8 @@
"java"
],
"variables": {
"SpecifyProgramArgs": "JavaDebug.SpecifyProgramArgs"
"SpecifyProgramArgs": "JavaDebug.SpecifyProgramArgs",
"PickJavaProcess": "JavaDebug.PickJavaProcess"
},
"configurationAttributes": {
"launch": {
Expand Down Expand Up @@ -605,7 +607,7 @@
"@types/lodash": "^4.14.137",
"@types/mocha": "^5.2.7",
"@types/node": "^8.10.51",
"@types/vscode": "1.38.0",
"@types/vscode": "1.42.0",
"cross-env": "^5.2.0",
"gulp": "^4.0.2",
"gulp-tslint": "^8.1.4",
Expand Down
80 changes: 44 additions & 36 deletions src/configurationProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@ import * as commands from "./commands";
import * as lsPlugin from "./languageServerPlugin";
import { addMoreHelpfulVMArgs, detectLaunchCommandStyle, validateRuntime } from "./launchCommand";
import { logger, Type } from "./logger";
import { resolveProcessId } from "./processPicker";
import { resolveJavaProcess } from "./processPicker";
import * as utility from "./utility";
import { VariableResolver } from "./variableResolver";

const platformNameMappings = {
win32: "windows",
Expand All @@ -27,9 +26,7 @@ const platformName = platformNameMappings[process.platform];
export class JavaDebugConfigurationProvider implements vscode.DebugConfigurationProvider {
private isUserSettingsDirty: boolean = true;
private debugHistory: MostRecentlyUsedHistory = new MostRecentlyUsedHistory();
private resolver: VariableResolver;
constructor() {
this.resolver = new VariableResolver();
vscode.workspace.onDidChangeConfiguration((event) => {
if (vscode.debug.activeDebugSession) {
this.isUserSettingsDirty = false;
Expand All @@ -52,13 +49,27 @@ export class JavaDebugConfigurationProvider implements vscode.DebugConfiguration
// Try to add all missing attributes to the debug configuration being launched.
public resolveDebugConfiguration(folder: vscode.WorkspaceFolder | undefined, config: vscode.DebugConfiguration, token?: vscode.CancellationToken):
vscode.ProviderResult<vscode.DebugConfiguration> {
// If no debug configuration is provided, then generate one in memory.
if (this.isEmptyConfig(config)) {
config.type = "java";
config.name = "Java Debug";
config.request = "launch";
}

return config;
}

// Try to add all missing attributes to the debug configuration being launched.
public resolveDebugConfigurationWithSubstitutedVariables(
folder: vscode.WorkspaceFolder | undefined,
config: vscode.DebugConfiguration,
token?: vscode.CancellationToken): vscode.ProviderResult<vscode.DebugConfiguration> {
const resolveDebugConfigurationHandler = instrumentOperation("resolveDebugConfiguration", (operationId: string) => {
try {
// See https://github.com/microsoft/vscode-java-debug/issues/778
// Merge the platform specific properties to the global config to simplify the subsequent resolving logic.
this.mergePlatformProperties(folder, config);
this.resolveVariables(folder, config);
return this.heuristicallyResolveDebugConfiguration(folder, config);
return this.resolveAndValidateDebugConfiguration(folder, config);
} catch (ex) {
utility.showErrorMessage({
message: String((ex && ex.message) || ex),
Expand Down Expand Up @@ -117,26 +128,6 @@ export class JavaDebugConfigurationProvider implements vscode.DebugConfiguration
}
}

private resolveVariables(folder: vscode.WorkspaceFolder, config: vscode.DebugConfiguration): void {
// all the properties whose values are string or array of string
const keys = ["mainClass", "args", "vmArgs", "modulePaths", "classPaths", "projectName",
"env", "sourcePaths", "encoding", "cwd", "hostName"];
if (!config) {
return;
}
for (const key of keys) {
if (config.hasOwnProperty(key)) {
const value = config[key];
if (_.isString(value)) {
config[key] = this.resolver.resolveString(folder ? folder.uri : undefined, value);
} else if (_.isArray(value)) {
config[key] = _.map(value, (item) =>
_.isString(item) ? this.resolver.resolveString(folder ? folder.uri : undefined, item) : item);
}
}
}
}

private constructLaunchConfigName(mainClass: string, projectName: string, cache: {}) {
const prefix = "Debug (Launch)-";
let name = prefix + mainClass.substr(mainClass.lastIndexOf(".") + 1);
Expand All @@ -152,7 +143,7 @@ export class JavaDebugConfigurationProvider implements vscode.DebugConfiguration
}
}

private async heuristicallyResolveDebugConfiguration(folder: vscode.WorkspaceFolder | undefined, config: vscode.DebugConfiguration) {
private async resolveAndValidateDebugConfiguration(folder: vscode.WorkspaceFolder | undefined, config: vscode.DebugConfiguration) {
try {
if (this.isUserSettingsDirty) {
this.isUserSettingsDirty = false;
Expand Down Expand Up @@ -233,18 +224,35 @@ export class JavaDebugConfigurationProvider implements vscode.DebugConfiguration
config.launcherScript = utility.getLauncherScriptPath();
}
} else if (config.request === "attach") {
if (config.processId !== undefined) {
try {
if (!(await resolveProcessId(config))) {
return undefined;
}
} catch (error) {
vscode.window.showErrorMessage(error.message ? error.message : String(error));
if (config.hostName && config.port) {
config.processId = undefined;
// Continue if the hostName and port are configured.
} else if (config.processId !== undefined) {
// tslint:disable-next-line
if (config.processId === "${command:PickJavaProcess}") {
return undefined;
}

const pid: number = Number(config.processId);
if (Number.isNaN(pid)) {
vscode.window.showErrorMessage(`The processId config '${config.processId}' is not a valid process id.`);
return undefined;
}
} else if (!config.hostName || !config.port) {

const javaProcess = await resolveJavaProcess(pid);
if (!javaProcess) {
vscode.window.showErrorMessage(`Attach to process: pid '${config.processId}' is not a debuggable Java process. `
+ `Please make sure the process has turned on debug mode using vmArgs like `
+ `'-agentlib:jdwp=transport=dt_socket,server=y,address=5005.'`);
return undefined;
}

config.processId = undefined;
config.hostName = javaProcess.hostName;
config.port = javaProcess.debugPort;
} else {
throw new utility.UserError({
message: "Please specify the host name and the port of the remote debuggee in the launch.json.",
message: "Please specify the hostName/port directly, or provide the processId of the remote debuggee in the launch.json.",
type: Type.USAGEERROR,
anchor: anchor.ATTACH_CONFIG_ERROR,
});
Expand Down
12 changes: 12 additions & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { handleHotCodeReplaceCustomEvent, initializeHotCodeReplace, NO_BUTTON, Y
import { JavaDebugAdapterDescriptorFactory } from "./javaDebugAdapterDescriptorFactory";
import { IMainMethod, resolveMainMethod } from "./languageServerPlugin";
import { logger, Type } from "./logger";
import { pickJavaProcess } from "./processPicker";
import { initializeThreadOperations } from "./threadOperations";
import * as utility from "./utility";

Expand All @@ -38,6 +39,17 @@ function initializeExtension(operationId: string, context: vscode.ExtensionConte
context.subscriptions.push(instrumentOperationAsVsCodeCommand("JavaDebug.SpecifyProgramArgs", async () => {
return specifyProgramArguments(context);
}));
context.subscriptions.push(instrumentOperationAsVsCodeCommand("JavaDebug.PickJavaProcess", async () => {
let javaProcess;
try {
javaProcess = await pickJavaProcess();
} catch (error) {
vscode.window.showErrorMessage(error.message ? error.message : String(error));
}

// tslint:disable-next-line
return javaProcess ? String(javaProcess.pid) : "${command:PickJavaProcess}";
}));
context.subscriptions.push(instrumentOperationAsVsCodeCommand("java.debug.hotCodeReplace", applyHCR));
context.subscriptions.push(instrumentOperationAsVsCodeCommand("java.debug.runJavaFile", async (uri: vscode.Uri) => {
await runJavaFile(uri, true);
Expand Down
30 changes: 3 additions & 27 deletions src/processPicker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,6 @@ interface IJavaProcess {
debugPort: number;
}

export async function resolveProcessId(config: DebugConfiguration): Promise<boolean> {
let javaProcess;
const pid: number = Number(config.processId);
// tslint:disable-next-line
if (!config.processId || Number.isNaN(pid)) {
javaProcess = await pickJavaProcess();
} else {
javaProcess = await resolveJavaProcess(pid);
if (!javaProcess) {
throw new Error(`Attach to process: pid '${config.processId}' is not a debuggable Java process. `
+ `Please make sure the process has turned on debug mode using vmArgs like `
+ `'-agentlib:jdwp=transport=dt_socket,server=y,address=5005.'`);
}
}

if (javaProcess) {
config.processId = undefined;
config.hostName = javaProcess.hostName;
config.port = javaProcess.debugPort;
}

return !!javaProcess;
}

function convertToJavaProcess(pid: number, command: string, args: string): IJavaProcess | undefined {
if (process.platform === "win32" && command.indexOf("\\??\\") === 0) {
// remove leading device specifier
Expand Down Expand Up @@ -68,7 +44,7 @@ function convertToJavaProcess(pid: number, command: string, args: string): IJava
}
}

async function pickJavaProcess(): Promise<IJavaProcess> {
export async function pickJavaProcess(): Promise<IJavaProcess> {
const javaProcesses: IJavaProcess[] = [];
try {
await getProcesses((pid: number, ppid: number, command: string, args: string, date: number) => {
Expand All @@ -82,7 +58,7 @@ async function pickJavaProcess(): Promise<IJavaProcess> {
}

if (!javaProcesses.length) {
throw new Error("Process picker: No debuggable Java process was found. Please make sure to use vmArgs like "
throw new Error("Process picker: Cannot find any debuggable Java process. Please make sure to use vmArgs like "
+ "'-agentlib:jdwp=transport=dt_socket,server=y,address=5005' to turn on debug mode when you start your "
+ "program.");
}
Expand All @@ -105,7 +81,7 @@ async function pickJavaProcess(): Promise<IJavaProcess> {
}
}

async function resolveJavaProcess(pid: number): Promise<IJavaProcess | undefined> {
export async function resolveJavaProcess(pid: number): Promise<IJavaProcess | undefined> {
const processTree = await getProcessTree(pid);
if (!processTree || processTree.pid !== pid) {
return undefined;
Expand Down
Loading