Add utility command to get the launch command length (#254)

Signed-off-by: Jinbo Wang <jinbwan@microsoft.com>
This commit is contained in:
Jinbo Wang 2019-02-21 14:52:56 +08:00 коммит произвёл GitHub
Родитель d3b8b3a630
Коммит ee889d9fbc
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
6 изменённых файлов: 150 добавлений и 83 удалений

Просмотреть файл

@ -12,6 +12,8 @@
package com.microsoft.java.debug.core.adapter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URI;
@ -25,11 +27,17 @@ import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.jar.Attributes;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import com.microsoft.java.debug.core.DebugException;
@ -287,4 +295,52 @@ public class AdapterUtils {
return uri;
}
}
/**
* Generate the classpath parameters to a temporary classpath.jar.
* @param classPaths - the classpath parameters
* @return the file path of the generate classpath.jar
* @throws IOException Some errors occur during generating the classpath.jar
*/
public static Path generateClasspathJar(String[] classPaths) throws IOException {
List<String> classpathUrls = new ArrayList<>();
for (String classpath : classPaths) {
classpathUrls.add(AdapterUtils.toUrl(classpath));
}
Manifest manifest = new Manifest();
Attributes attributes = manifest.getMainAttributes();
attributes.put(Attributes.Name.MANIFEST_VERSION, "1.0");
// In jar manifest, the absolute path C:\a.jar should be converted to the url style file:///C:/a.jar
attributes.put(Attributes.Name.CLASS_PATH, String.join(" ", classpathUrls));
Path tempfile = Files.createTempFile("classpath_", ".jar");
JarOutputStream jar = new JarOutputStream(new FileOutputStream(tempfile.toFile()), manifest);
jar.close();
return tempfile;
}
/**
* Generate the classpath parameters to a temporary argfile file.
* @param classPaths - the classpath parameters
* @param modulePaths - the modulepath parameters
* @return the file path of the generated argfile
* @throws IOException Some errors occur during generating the argfile
*/
public static Path generateArgfile(String[] classPaths, String[] modulePaths) throws IOException {
String argfile = "";
if (ArrayUtils.isNotEmpty(classPaths)) {
argfile = "-classpath \"" + String.join(File.pathSeparator, classPaths) + "\"";
}
if (ArrayUtils.isNotEmpty(modulePaths)) {
argfile = " --module-path \"" + String.join(File.pathSeparator, modulePaths) + "\"";
}
argfile = argfile.replace("\\", "\\\\");
Path tempfile = Files.createTempFile("java_", ".argfile");
Files.write(tempfile, argfile.getBytes());
return tempfile;
}
}

Просмотреть файл

@ -16,6 +16,7 @@ import java.nio.file.Files;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
@ -86,7 +87,7 @@ public abstract class AbstractDisconnectRequestHandler implements IDebugRequestH
}
try {
Thread.sleep(1000);
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// do nothing.
}

Просмотреть файл

@ -12,12 +12,10 @@
package com.microsoft.java.debug.core.adapter.handler;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
@ -26,9 +24,6 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.CompletableFuture;
import java.util.jar.Attributes;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.logging.Level;
import java.util.logging.Logger;
@ -97,59 +92,31 @@ public class LaunchRequestHandler implements IDebugRequestHandler {
activeLaunchHandler.preLaunch(launchArguments, context);
Path tempfile = null;
// Use the specified cli style to launch the program.
if (launchArguments.shortenCommandLine == ShortenApproach.JARMANIFEST) {
if (ArrayUtils.isNotEmpty(launchArguments.classPaths)) {
List<String> classpathUrls = new ArrayList<>();
for (String classpath : launchArguments.classPaths) {
try {
classpathUrls.add(AdapterUtils.toUrl(classpath));
} catch (IllegalArgumentException | MalformedURLException ex) {
logger.log(Level.SEVERE, String.format("Failed to launch the program with jarmanifest style: %s", ex.toString(), ex));
throw AdapterUtils.createCompletionException("Failed to launch the program with jarmanifest style: " + ex.toString(),
ErrorCode.LAUNCH_FAILURE, ex);
}
}
try {
tempfile = Files.createTempFile("classpath_", ".jar");
Manifest manifest = new Manifest();
Attributes attributes = manifest.getMainAttributes();
attributes.put(Attributes.Name.MANIFEST_VERSION, "1.0");
// In jar manifest, the absolute path C:\a.jar should be converted to the url style file:///C:/a.jar
attributes.put(Attributes.Name.CLASS_PATH, String.join(" ", classpathUrls));
JarOutputStream jar = new JarOutputStream(new FileOutputStream(tempfile.toFile()), manifest);
jar.close();
Path tempfile = AdapterUtils.generateClasspathJar(launchArguments.classPaths);
launchArguments.vmArgs += " -cp \"" + tempfile.toAbsolutePath().toString() + "\"";
launchArguments.classPaths = new String[0];
context.setClasspathJar(tempfile);
} catch (IllegalArgumentException | MalformedURLException ex) {
logger.log(Level.SEVERE, String.format("Failed to launch the program with jarmanifest style: %s", ex.toString(), ex));
throw AdapterUtils.createCompletionException("Failed to launch the program with jarmanifest style: " + ex.toString(),
ErrorCode.LAUNCH_FAILURE, ex);
} catch (IOException e) {
logger.log(Level.SEVERE, String.format("Failed to create a temp classpath.jar: %s", e.toString()), e);
tempfile = null;
}
}
} else if (launchArguments.shortenCommandLine == ShortenApproach.ARGFILE) {
try {
tempfile = Files.createTempFile("java_", ".argfile");
String argfile = "";
if (ArrayUtils.isNotEmpty(launchArguments.classPaths)) {
argfile = "-classpath \"" + String.join(File.pathSeparator, launchArguments.classPaths) + "\"";
}
if (ArrayUtils.isNotEmpty(launchArguments.modulePaths)) {
argfile = " --module-path \"" + String.join(File.pathSeparator, launchArguments.modulePaths) + "\"";
}
argfile = argfile.replace("\\", "\\\\");
Files.write(tempfile, argfile.getBytes());
Path tempfile = AdapterUtils.generateArgfile(launchArguments.classPaths, launchArguments.modulePaths);
launchArguments.vmArgs += " @" + tempfile.toAbsolutePath().toString();
launchArguments.classPaths = new String[0];
launchArguments.modulePaths = new String[0];
context.setArgsfile(tempfile);
} catch (IOException e) {
logger.log(Level.SEVERE, String.format("Failed to create a temp argfile: %s", e.toString()), e);
tempfile = null;
}
}
@ -161,7 +128,14 @@ public class LaunchRequestHandler implements IDebugRequestHandler {
});
}
protected static String[] constructLaunchCommands(LaunchArguments launchArguments, boolean serverMode, String address) {
/**
* Construct the Java command lines based on the given launch arguments.
* @param launchArguments - The launch arguments
* @param serverMode - whether to enable the debug port with server mode
* @param address - the debug port
* @return the command arrays
*/
public static String[] constructLaunchCommands(LaunchArguments launchArguments, boolean serverMode, String address) {
String slash = System.getProperty("file.separator");
List<String> launchCmds = new ArrayList<>();

Просмотреть файл

@ -9,12 +9,9 @@
<command id="vscode.java.buildWorkspace"/>
<command id="vscode.java.fetchUsageData"/>
<command id="vscode.java.updateDebugSettings"/>
<command
id="vscode.java.validateLaunchConfig">
</command>
<command
id="vscode.java.resolveMainMethod">
</command>
<command id="vscode.java.validateLaunchConfig"/>
<command id="vscode.java.resolveMainMethod"/>
<command id="vscode.java.inferLaunchCommandLength"/>
</delegateCommandHandler>
</extension>
</plugin>

Просмотреть файл

@ -17,47 +17,48 @@ import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.ls.core.internal.IDelegateCommandHandler;
import com.microsoft.java.debug.core.UsageDataStore;
import com.microsoft.java.debug.core.protocol.JsonUtils;
import com.microsoft.java.debug.core.protocol.Requests.LaunchArguments;
public class JavaDebugDelegateCommandHandler implements IDelegateCommandHandler {
public static String FETCH_USER_DATA = "vscode.java.fetchUsageData";
public static String DEBUG_STARTSESSION = "vscode.java.startDebugSession";
public static String RESOLVE_CLASSPATH = "vscode.java.resolveClasspath";
public static String RESOLVE_MAINCLASS = "vscode.java.resolveMainClass";
public static String BUILD_WORKSPACE = "vscode.java.buildWorkspace";
public static String UPDATE_DEBUG_SETTINGS = "vscode.java.updateDebugSettings";
public static String VALIDATE_LAUNCHCONFIG = "vscode.java.validateLaunchConfig";
public static String RESOLVE_MAINMETHOD = "vscode.java.resolveMainMethod";
public static final String FETCH_USER_DATA = "vscode.java.fetchUsageData";
public static final String DEBUG_STARTSESSION = "vscode.java.startDebugSession";
public static final String RESOLVE_CLASSPATH = "vscode.java.resolveClasspath";
public static final String RESOLVE_MAINCLASS = "vscode.java.resolveMainClass";
public static final String BUILD_WORKSPACE = "vscode.java.buildWorkspace";
public static final String UPDATE_DEBUG_SETTINGS = "vscode.java.updateDebugSettings";
public static final String VALIDATE_LAUNCHCONFIG = "vscode.java.validateLaunchConfig";
public static final String RESOLVE_MAINMETHOD = "vscode.java.resolveMainMethod";
public static final String INFER_LAUNCH_COMMAND_LENGTH = "vscode.java.inferLaunchCommandLength";
@Override
public Object executeCommand(String commandId, List<Object> arguments, IProgressMonitor progress) throws Exception {
if (DEBUG_STARTSESSION.equals(commandId)) {
IDebugServer debugServer = JavaDebugServer.getInstance();
debugServer.start();
return debugServer.getPort();
} else if (RESOLVE_CLASSPATH.equals(commandId)) {
ResolveClasspathsHandler handler = new ResolveClasspathsHandler();
return handler.resolveClasspaths(arguments);
} else if (RESOLVE_MAINCLASS.equals(commandId)) {
ResolveMainClassHandler handler = new ResolveMainClassHandler();
return handler.resolveMainClass(arguments);
} else if (BUILD_WORKSPACE.equals(commandId)) {
// TODO
} else if (FETCH_USER_DATA.equals(commandId)) {
return UsageDataStore.getInstance().fetchAll();
} else if (UPDATE_DEBUG_SETTINGS.equals(commandId)) {
return DebugSettingUtils.configDebugSettings(arguments);
} else if (VALIDATE_LAUNCHCONFIG.equals(commandId)) {
return new ResolveMainClassHandler().validateLaunchConfig(arguments);
} else if (RESOLVE_MAINMETHOD.equals(commandId)) {
return ResolveMainMethodHandler.resolveMainMethods(arguments);
switch (commandId) {
case DEBUG_STARTSESSION:
IDebugServer debugServer = JavaDebugServer.getInstance();
debugServer.start();
return debugServer.getPort();
case RESOLVE_CLASSPATH:
ResolveClasspathsHandler handler = new ResolveClasspathsHandler();
return handler.resolveClasspaths(arguments);
case RESOLVE_MAINCLASS:
ResolveMainClassHandler resolveMainClassHandler = new ResolveMainClassHandler();
return resolveMainClassHandler.resolveMainClass(arguments);
case BUILD_WORKSPACE:
// TODO
break;
case FETCH_USER_DATA:
return UsageDataStore.getInstance().fetchAll();
case UPDATE_DEBUG_SETTINGS:
return DebugSettingUtils.configDebugSettings(arguments);
case VALIDATE_LAUNCHCONFIG:
return new ResolveMainClassHandler().validateLaunchConfig(arguments);
case RESOLVE_MAINMETHOD:
return ResolveMainMethodHandler.resolveMainMethods(arguments);
case INFER_LAUNCH_COMMAND_LENGTH:
return LaunchCommandHandler.getLaunchCommandLength(JsonUtils.fromJson((String) arguments.get(0), LaunchArguments.class));
default:
break;
}
throw new UnsupportedOperationException(String.format("Java debug plugin doesn't support the command '%s'.", commandId));

Просмотреть файл

@ -0,0 +1,38 @@
/*******************************************************************************
* Copyright (c) 2019 Microsoft Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Microsoft Corporation - initial API and implementation
*******************************************************************************/
package com.microsoft.java.debug.plugin.internal;
import java.nio.charset.StandardCharsets;
import org.apache.commons.lang3.StringUtils;
import com.microsoft.java.debug.core.adapter.handler.LaunchRequestHandler;
import com.microsoft.java.debug.core.protocol.Requests.CONSOLE;
import com.microsoft.java.debug.core.protocol.Requests.LaunchArguments;
public class LaunchCommandHandler {
/**
* Get the approximate command line length based on the launch arguments.
* @param launchArguments - the launch arguments
* @return the approximate command line length
*/
public static int getLaunchCommandLength(LaunchArguments launchArguments) {
String encoding = StringUtils.isBlank(launchArguments.encoding) ? StandardCharsets.UTF_8.name() : launchArguments.encoding;
launchArguments.vmArgs += String.format(" -Dfile.encoding=%s", encoding);
String address = launchArguments.noDebug ? "" : "888888";
String[] commands = LaunchRequestHandler.constructLaunchCommands(launchArguments, false, address);
int cwdLength = launchArguments.console == CONSOLE.internalConsole ? 0 : StringUtils.length("cd " + launchArguments.cwd + " && ");
return cwdLength + String.join(" ", commands).length();
}
}