Skip to content

Commit ee889d9

Browse files
Add utility command to get the launch command length (#254)
Signed-off-by: Jinbo Wang <[email protected]>
1 parent d3b8b3a commit ee889d9

File tree

6 files changed

+150
-83
lines changed

6 files changed

+150
-83
lines changed

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/AdapterUtils.java

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
package com.microsoft.java.debug.core.adapter;
1313

1414
import java.io.File;
15+
import java.io.FileOutputStream;
16+
import java.io.IOException;
1517
import java.io.UnsupportedEncodingException;
1618
import java.net.MalformedURLException;
1719
import java.net.URI;
@@ -25,11 +27,17 @@
2527
import java.nio.file.Paths;
2628
import java.security.MessageDigest;
2729
import java.security.NoSuchAlgorithmException;
30+
import java.util.ArrayList;
31+
import java.util.List;
2832
import java.util.concurrent.CompletableFuture;
2933
import java.util.concurrent.CompletionException;
34+
import java.util.jar.Attributes;
35+
import java.util.jar.JarOutputStream;
36+
import java.util.jar.Manifest;
3037
import java.util.regex.Matcher;
3138
import java.util.regex.Pattern;
3239

40+
import org.apache.commons.lang3.ArrayUtils;
3341
import org.apache.commons.lang3.StringUtils;
3442

3543
import com.microsoft.java.debug.core.DebugException;
@@ -287,4 +295,52 @@ public static String decodeURIComponent(String uri) {
287295
return uri;
288296
}
289297
}
298+
299+
/**
300+
* Generate the classpath parameters to a temporary classpath.jar.
301+
* @param classPaths - the classpath parameters
302+
* @return the file path of the generate classpath.jar
303+
* @throws IOException Some errors occur during generating the classpath.jar
304+
*/
305+
public static Path generateClasspathJar(String[] classPaths) throws IOException {
306+
List<String> classpathUrls = new ArrayList<>();
307+
for (String classpath : classPaths) {
308+
classpathUrls.add(AdapterUtils.toUrl(classpath));
309+
}
310+
311+
Manifest manifest = new Manifest();
312+
Attributes attributes = manifest.getMainAttributes();
313+
attributes.put(Attributes.Name.MANIFEST_VERSION, "1.0");
314+
// In jar manifest, the absolute path C:\a.jar should be converted to the url style file:///C:/a.jar
315+
attributes.put(Attributes.Name.CLASS_PATH, String.join(" ", classpathUrls));
316+
Path tempfile = Files.createTempFile("classpath_", ".jar");
317+
JarOutputStream jar = new JarOutputStream(new FileOutputStream(tempfile.toFile()), manifest);
318+
jar.close();
319+
320+
return tempfile;
321+
}
322+
323+
/**
324+
* Generate the classpath parameters to a temporary argfile file.
325+
* @param classPaths - the classpath parameters
326+
* @param modulePaths - the modulepath parameters
327+
* @return the file path of the generated argfile
328+
* @throws IOException Some errors occur during generating the argfile
329+
*/
330+
public static Path generateArgfile(String[] classPaths, String[] modulePaths) throws IOException {
331+
String argfile = "";
332+
if (ArrayUtils.isNotEmpty(classPaths)) {
333+
argfile = "-classpath \"" + String.join(File.pathSeparator, classPaths) + "\"";
334+
}
335+
336+
if (ArrayUtils.isNotEmpty(modulePaths)) {
337+
argfile = " --module-path \"" + String.join(File.pathSeparator, modulePaths) + "\"";
338+
}
339+
340+
argfile = argfile.replace("\\", "\\\\");
341+
Path tempfile = Files.createTempFile("java_", ".argfile");
342+
Files.write(tempfile, argfile.getBytes());
343+
344+
return tempfile;
345+
}
290346
}

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/AbstractDisconnectRequestHandler.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import java.util.Arrays;
1717
import java.util.List;
1818
import java.util.concurrent.CompletableFuture;
19+
import java.util.concurrent.TimeUnit;
1920
import java.util.logging.Level;
2021
import java.util.logging.Logger;
2122

@@ -86,7 +87,7 @@ private void destroyLaunchFiles(IDebugAdapterContext context) {
8687
}
8788

8889
try {
89-
Thread.sleep(1000);
90+
TimeUnit.SECONDS.sleep(1);
9091
} catch (InterruptedException e) {
9192
// do nothing.
9293
}

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/LaunchRequestHandler.java

Lines changed: 14 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,10 @@
1212
package com.microsoft.java.debug.core.adapter.handler;
1313

1414
import java.io.File;
15-
import java.io.FileOutputStream;
1615
import java.io.IOException;
1716
import java.net.MalformedURLException;
1817
import java.nio.charset.Charset;
1918
import java.nio.charset.StandardCharsets;
20-
import java.nio.file.Files;
2119
import java.nio.file.Path;
2220
import java.util.ArrayList;
2321
import java.util.Arrays;
@@ -26,9 +24,6 @@
2624
import java.util.Map;
2725
import java.util.Map.Entry;
2826
import java.util.concurrent.CompletableFuture;
29-
import java.util.jar.Attributes;
30-
import java.util.jar.JarOutputStream;
31-
import java.util.jar.Manifest;
3227
import java.util.logging.Level;
3328
import java.util.logging.Logger;
3429

@@ -97,59 +92,31 @@ protected CompletableFuture<Response> handleLaunchCommand(Arguments arguments, R
9792

9893
activeLaunchHandler.preLaunch(launchArguments, context);
9994

100-
Path tempfile = null;
10195
// Use the specified cli style to launch the program.
10296
if (launchArguments.shortenCommandLine == ShortenApproach.JARMANIFEST) {
10397
if (ArrayUtils.isNotEmpty(launchArguments.classPaths)) {
104-
List<String> classpathUrls = new ArrayList<>();
105-
for (String classpath : launchArguments.classPaths) {
106-
try {
107-
classpathUrls.add(AdapterUtils.toUrl(classpath));
108-
} catch (IllegalArgumentException | MalformedURLException ex) {
109-
logger.log(Level.SEVERE, String.format("Failed to launch the program with jarmanifest style: %s", ex.toString(), ex));
110-
throw AdapterUtils.createCompletionException("Failed to launch the program with jarmanifest style: " + ex.toString(),
111-
ErrorCode.LAUNCH_FAILURE, ex);
112-
}
113-
}
114-
11598
try {
116-
tempfile = Files.createTempFile("classpath_", ".jar");
117-
Manifest manifest = new Manifest();
118-
Attributes attributes = manifest.getMainAttributes();
119-
attributes.put(Attributes.Name.MANIFEST_VERSION, "1.0");
120-
// In jar manifest, the absolute path C:\a.jar should be converted to the url style file:///C:/a.jar
121-
attributes.put(Attributes.Name.CLASS_PATH, String.join(" ", classpathUrls));
122-
JarOutputStream jar = new JarOutputStream(new FileOutputStream(tempfile.toFile()), manifest);
123-
jar.close();
99+
Path tempfile = AdapterUtils.generateClasspathJar(launchArguments.classPaths);
124100
launchArguments.vmArgs += " -cp \"" + tempfile.toAbsolutePath().toString() + "\"";
125101
launchArguments.classPaths = new String[0];
126102
context.setClasspathJar(tempfile);
103+
} catch (IllegalArgumentException | MalformedURLException ex) {
104+
logger.log(Level.SEVERE, String.format("Failed to launch the program with jarmanifest style: %s", ex.toString(), ex));
105+
throw AdapterUtils.createCompletionException("Failed to launch the program with jarmanifest style: " + ex.toString(),
106+
ErrorCode.LAUNCH_FAILURE, ex);
127107
} catch (IOException e) {
128108
logger.log(Level.SEVERE, String.format("Failed to create a temp classpath.jar: %s", e.toString()), e);
129-
tempfile = null;
130109
}
131110
}
132111
} else if (launchArguments.shortenCommandLine == ShortenApproach.ARGFILE) {
133112
try {
134-
tempfile = Files.createTempFile("java_", ".argfile");
135-
String argfile = "";
136-
if (ArrayUtils.isNotEmpty(launchArguments.classPaths)) {
137-
argfile = "-classpath \"" + String.join(File.pathSeparator, launchArguments.classPaths) + "\"";
138-
}
139-
140-
if (ArrayUtils.isNotEmpty(launchArguments.modulePaths)) {
141-
argfile = " --module-path \"" + String.join(File.pathSeparator, launchArguments.modulePaths) + "\"";
142-
}
143-
144-
argfile = argfile.replace("\\", "\\\\");
145-
Files.write(tempfile, argfile.getBytes());
113+
Path tempfile = AdapterUtils.generateArgfile(launchArguments.classPaths, launchArguments.modulePaths);
146114
launchArguments.vmArgs += " @" + tempfile.toAbsolutePath().toString();
147115
launchArguments.classPaths = new String[0];
148116
launchArguments.modulePaths = new String[0];
149117
context.setArgsfile(tempfile);
150118
} catch (IOException e) {
151119
logger.log(Level.SEVERE, String.format("Failed to create a temp argfile: %s", e.toString()), e);
152-
tempfile = null;
153120
}
154121
}
155122

@@ -161,7 +128,14 @@ protected CompletableFuture<Response> handleLaunchCommand(Arguments arguments, R
161128
});
162129
}
163130

164-
protected static String[] constructLaunchCommands(LaunchArguments launchArguments, boolean serverMode, String address) {
131+
/**
132+
* Construct the Java command lines based on the given launch arguments.
133+
* @param launchArguments - The launch arguments
134+
* @param serverMode - whether to enable the debug port with server mode
135+
* @param address - the debug port
136+
* @return the command arrays
137+
*/
138+
public static String[] constructLaunchCommands(LaunchArguments launchArguments, boolean serverMode, String address) {
165139
String slash = System.getProperty("file.separator");
166140

167141
List<String> launchCmds = new ArrayList<>();

com.microsoft.java.debug.plugin/plugin.xml

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,9 @@
99
<command id="vscode.java.buildWorkspace"/>
1010
<command id="vscode.java.fetchUsageData"/>
1111
<command id="vscode.java.updateDebugSettings"/>
12-
<command
13-
id="vscode.java.validateLaunchConfig">
14-
</command>
15-
<command
16-
id="vscode.java.resolveMainMethod">
17-
</command>
12+
<command id="vscode.java.validateLaunchConfig"/>
13+
<command id="vscode.java.resolveMainMethod"/>
14+
<command id="vscode.java.inferLaunchCommandLength"/>
1815
</delegateCommandHandler>
1916
</extension>
2017
</plugin>

com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JavaDebugDelegateCommandHandler.java

Lines changed: 37 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -17,47 +17,48 @@
1717
import org.eclipse.jdt.ls.core.internal.IDelegateCommandHandler;
1818

1919
import com.microsoft.java.debug.core.UsageDataStore;
20+
import com.microsoft.java.debug.core.protocol.JsonUtils;
21+
import com.microsoft.java.debug.core.protocol.Requests.LaunchArguments;
2022

2123
public class JavaDebugDelegateCommandHandler implements IDelegateCommandHandler {
22-
23-
public static String FETCH_USER_DATA = "vscode.java.fetchUsageData";
24-
25-
public static String DEBUG_STARTSESSION = "vscode.java.startDebugSession";
26-
27-
public static String RESOLVE_CLASSPATH = "vscode.java.resolveClasspath";
28-
29-
public static String RESOLVE_MAINCLASS = "vscode.java.resolveMainClass";
30-
31-
public static String BUILD_WORKSPACE = "vscode.java.buildWorkspace";
32-
33-
public static String UPDATE_DEBUG_SETTINGS = "vscode.java.updateDebugSettings";
34-
35-
public static String VALIDATE_LAUNCHCONFIG = "vscode.java.validateLaunchConfig";
36-
37-
public static String RESOLVE_MAINMETHOD = "vscode.java.resolveMainMethod";
24+
public static final String FETCH_USER_DATA = "vscode.java.fetchUsageData";
25+
public static final String DEBUG_STARTSESSION = "vscode.java.startDebugSession";
26+
public static final String RESOLVE_CLASSPATH = "vscode.java.resolveClasspath";
27+
public static final String RESOLVE_MAINCLASS = "vscode.java.resolveMainClass";
28+
public static final String BUILD_WORKSPACE = "vscode.java.buildWorkspace";
29+
public static final String UPDATE_DEBUG_SETTINGS = "vscode.java.updateDebugSettings";
30+
public static final String VALIDATE_LAUNCHCONFIG = "vscode.java.validateLaunchConfig";
31+
public static final String RESOLVE_MAINMETHOD = "vscode.java.resolveMainMethod";
32+
public static final String INFER_LAUNCH_COMMAND_LENGTH = "vscode.java.inferLaunchCommandLength";
3833

3934
@Override
4035
public Object executeCommand(String commandId, List<Object> arguments, IProgressMonitor progress) throws Exception {
41-
if (DEBUG_STARTSESSION.equals(commandId)) {
42-
IDebugServer debugServer = JavaDebugServer.getInstance();
43-
debugServer.start();
44-
return debugServer.getPort();
45-
} else if (RESOLVE_CLASSPATH.equals(commandId)) {
46-
ResolveClasspathsHandler handler = new ResolveClasspathsHandler();
47-
return handler.resolveClasspaths(arguments);
48-
} else if (RESOLVE_MAINCLASS.equals(commandId)) {
49-
ResolveMainClassHandler handler = new ResolveMainClassHandler();
50-
return handler.resolveMainClass(arguments);
51-
} else if (BUILD_WORKSPACE.equals(commandId)) {
52-
// TODO
53-
} else if (FETCH_USER_DATA.equals(commandId)) {
54-
return UsageDataStore.getInstance().fetchAll();
55-
} else if (UPDATE_DEBUG_SETTINGS.equals(commandId)) {
56-
return DebugSettingUtils.configDebugSettings(arguments);
57-
} else if (VALIDATE_LAUNCHCONFIG.equals(commandId)) {
58-
return new ResolveMainClassHandler().validateLaunchConfig(arguments);
59-
} else if (RESOLVE_MAINMETHOD.equals(commandId)) {
60-
return ResolveMainMethodHandler.resolveMainMethods(arguments);
36+
switch (commandId) {
37+
case DEBUG_STARTSESSION:
38+
IDebugServer debugServer = JavaDebugServer.getInstance();
39+
debugServer.start();
40+
return debugServer.getPort();
41+
case RESOLVE_CLASSPATH:
42+
ResolveClasspathsHandler handler = new ResolveClasspathsHandler();
43+
return handler.resolveClasspaths(arguments);
44+
case RESOLVE_MAINCLASS:
45+
ResolveMainClassHandler resolveMainClassHandler = new ResolveMainClassHandler();
46+
return resolveMainClassHandler.resolveMainClass(arguments);
47+
case BUILD_WORKSPACE:
48+
// TODO
49+
break;
50+
case FETCH_USER_DATA:
51+
return UsageDataStore.getInstance().fetchAll();
52+
case UPDATE_DEBUG_SETTINGS:
53+
return DebugSettingUtils.configDebugSettings(arguments);
54+
case VALIDATE_LAUNCHCONFIG:
55+
return new ResolveMainClassHandler().validateLaunchConfig(arguments);
56+
case RESOLVE_MAINMETHOD:
57+
return ResolveMainMethodHandler.resolveMainMethods(arguments);
58+
case INFER_LAUNCH_COMMAND_LENGTH:
59+
return LaunchCommandHandler.getLaunchCommandLength(JsonUtils.fromJson((String) arguments.get(0), LaunchArguments.class));
60+
default:
61+
break;
6162
}
6263

6364
throw new UnsupportedOperationException(String.format("Java debug plugin doesn't support the command '%s'.", commandId));
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2019 Microsoft Corporation and others.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v1.0
5+
* which accompanies this distribution, and is available at
6+
* http://www.eclipse.org/legal/epl-v10.html
7+
*
8+
* Contributors:
9+
* Microsoft Corporation - initial API and implementation
10+
*******************************************************************************/
11+
12+
package com.microsoft.java.debug.plugin.internal;
13+
14+
import java.nio.charset.StandardCharsets;
15+
16+
import org.apache.commons.lang3.StringUtils;
17+
18+
import com.microsoft.java.debug.core.adapter.handler.LaunchRequestHandler;
19+
import com.microsoft.java.debug.core.protocol.Requests.CONSOLE;
20+
import com.microsoft.java.debug.core.protocol.Requests.LaunchArguments;
21+
22+
public class LaunchCommandHandler {
23+
24+
/**
25+
* Get the approximate command line length based on the launch arguments.
26+
* @param launchArguments - the launch arguments
27+
* @return the approximate command line length
28+
*/
29+
public static int getLaunchCommandLength(LaunchArguments launchArguments) {
30+
String encoding = StringUtils.isBlank(launchArguments.encoding) ? StandardCharsets.UTF_8.name() : launchArguments.encoding;
31+
launchArguments.vmArgs += String.format(" -Dfile.encoding=%s", encoding);
32+
String address = launchArguments.noDebug ? "" : "888888";
33+
String[] commands = LaunchRequestHandler.constructLaunchCommands(launchArguments, false, address);
34+
int cwdLength = launchArguments.console == CONSOLE.internalConsole ? 0 : StringUtils.length("cd " + launchArguments.cwd + " && ");
35+
return cwdLength + String.join(" ", commands).length();
36+
}
37+
38+
}

0 commit comments

Comments
 (0)