[platform] adds dynamic VM parameters support in classpath file mode

This commit is contained in:
Roman Shevchenko
2016-12-28 15:04:47 +01:00
parent 07a357662a
commit b8f9d2f14b
4 changed files with 114 additions and 61 deletions
@@ -151,7 +151,7 @@ public class CommandLineWrapper {
}
/**
* args: "classpath file" [ @vm_params "VM options file" ] "main class" [ args ... ]
* args: "classpath file" [ @vm_params "VM options file" ] [ @app_params "args file" ] "main class" [ args ... ]
* @noinspection Duplicates, ResultOfMethodCallIgnored
*/
private static AppData loadMainClassWithCustomLoader(File classpathFile, String[] args) throws Exception {
@@ -175,11 +175,9 @@ public class CommandLineWrapper {
int startArgsIdx = 2;
List properties = Collections.EMPTY_LIST;
if (args.length >= 3 && "@vm_params".equals(args[1])) {
startArgsIdx = 4;
File vmParamsFile = new File(args[2]);
BufferedReader vmParamsReader = new BufferedReader(new FileReader(args[2]));
if (args.length > startArgsIdx && "@vm_params".equals(args[startArgsIdx - 1])) {
File vmParamsFile = new File(args[startArgsIdx]);
BufferedReader vmParamsReader = new BufferedReader(new FileReader(vmParamsFile));
try {
properties = new ArrayList();
String property;
@@ -191,12 +189,35 @@ public class CommandLineWrapper {
vmParamsReader.close();
vmParamsFile.delete();
}
startArgsIdx += 2;
}
String[] mainArgs;
if (args.length > startArgsIdx && "@app_params".equals(args[startArgsIdx - 1])) {
File appParamsFile = new File(args[startArgsIdx]);
BufferedReader appParamsReader = new BufferedReader(new FileReader(appParamsFile));
try {
List list = new ArrayList();
String arg;
while ((arg = appParamsReader.readLine()) != null) {
list.add(arg);
}
mainArgs = (String[])list.toArray(new String[list.size()]);
}
finally {
appParamsReader.close();
appParamsFile.delete();
}
startArgsIdx += 2;
}
else {
mainArgs = new String[args.length - startArgsIdx];
System.arraycopy(args, startArgsIdx, mainArgs, 0, mainArgs.length);
}
String mainClassName = args[startArgsIdx - 1];
String[] mainArgs = new String[args.length - startArgsIdx];
System.arraycopy(args, startArgsIdx, mainArgs, 0, mainArgs.length);
ClassLoader loader = new URLClassLoader((URL[])classpathUrls.toArray(new URL[classpathUrls.size()]), null);
String systemLoaderName = System.getProperty("java.system.class.loader");
if (systemLoaderName != null) {
@@ -53,9 +53,7 @@ class CommandLineWrapperRunTest : BareTestFixtureTestCase() {
parameters.setUseDynamicClasspath(dynamicCp)
parameters.setUseClasspathJar(classPathJar)
parameters.setUseDynamicVMOptions(dynamicArgs)
if (classPathJar) {
parameters.setPassProgramParametersViaClasspathJar(dynamicArgs)
}
parameters.setUseDynamicParameters(dynamicArgs)
val command = parameters.toCommandLine()
val out = ExecUtil.execAndGetOutput(command)
@@ -45,8 +45,8 @@ public class SimpleJavaParameters extends SimpleProgramParameters {
private Charset myCharset = CharsetToolkit.getDefaultSystemCharset();
private boolean myUseDynamicClasspath;
private boolean myUseDynamicVMOptions;
private boolean myUseClasspathJar = false;
private boolean myPassProgramParametersViaClasspathJar;
private boolean myUseDynamicParameters;
private boolean myUseClasspathJar;
private String myJarPath;
@Nullable
@@ -111,35 +111,29 @@ public class SimpleJavaParameters extends SimpleProgramParameters {
return myUseDynamicVMOptions;
}
/** Allows to pass system properties via a temporary file in order to avoid "too long command line" problem. */
public void setUseDynamicVMOptions(boolean useDynamicVMOptions) {
myUseDynamicVMOptions = useDynamicVMOptions;
}
public boolean isDynamicParameters() {
return myUseDynamicParameters;
}
/** Allows to pass program parameters via a temporary file in order to avoid "too long command line" problem. */
public void setUseDynamicParameters(boolean useDynamicParameters) {
myUseDynamicParameters = useDynamicParameters;
}
public boolean isUseClasspathJar() {
return myUseClasspathJar;
}
/**
* Call this method and pass {@code true} to pass classpath of the application via MANIFEST.MF file in a specially generated classpath.jar
* archive instead of passing it via -classpath command line option. This may be needed to avoid problems with too long command line on Windows.
*/
/** Allows to use a specially crafted .jar file instead of a custom class loader to pass classpath/properties/parameters. */
public void setUseClasspathJar(boolean useClasspathJar) {
myUseClasspathJar = useClasspathJar;
}
public boolean isPassProgramParametersViaClasspathJar() {
return myPassProgramParametersViaClasspathJar;
}
/**
* Call this method and pass {@code true} to pass program parameters via attribute in MANIFEST.MF of the classpath jar instead of passing
* them via command line. This may be needed to avoid problems with too long command line on Windows.
*/
public void setPassProgramParametersViaClasspathJar(@SuppressWarnings("SameParameterValue") boolean passProgramParametersViaClasspathJar) {
LOG.assertTrue(myUseClasspathJar);
myPassProgramParametersViaClasspathJar = passProgramParametersViaClasspathJar;
}
public String getJarPath() {
return myJarPath;
}
@@ -163,4 +157,17 @@ public class SimpleJavaParameters extends SimpleProgramParameters {
ProcessTerminatedListener.attach(processHandler);
return processHandler;
}
//<editor-fold desc="Deprecated stuff.">
/** @deprecated use {@link #isDynamicParameters()} (to be removed in IDEA 2018) */
public boolean isPassProgramParametersViaClasspathJar() {
return isDynamicParameters();
}
/** @deprecated use {@link #setUseDynamicParameters(boolean)} (to be removed in IDEA 2018) */
public void setPassProgramParametersViaClasspathJar(@SuppressWarnings("SameParameterValue") boolean passProgramParametersViaClasspathJar) {
LOG.assertTrue(myUseClasspathJar);
setUseDynamicParameters(passProgramParametersViaClasspathJar);
}
//</editor-fold>
}
@@ -167,17 +167,16 @@ public class JdkUtil {
commandLine.withParentEnvironmentType(javaParameters.isPassParentEnvs() ? ParentEnvironmentType.CONSOLE : ParentEnvironmentType.NONE);
final Class commandLineWrapper;
boolean passProgramParametersViaClassPathJar = false;
boolean dynamicParameters = false;
if (javaParameters.isDynamicClasspath() &&
!explicitClassPath(vmParameters) &&
javaParameters.getModulePath().isEmpty() &&
(commandLineWrapper = getCommandLineWrapperClass()) != null) {
if (isClassPathJarEnabled(javaParameters, PathUtil.getJarPathForClass(ClassPath.class))) {
passProgramParametersViaClassPathJar = javaParameters.isPassProgramParametersViaClasspathJar();
appendJarClasspathParams(javaParameters, commandLine, vmParameters, commandLineWrapper, passProgramParametersViaClassPathJar);
dynamicParameters = setClasspathJarParams(javaParameters, commandLine, vmParameters, commandLineWrapper);
}
else {
appendOldCommandLineWrapper(javaParameters, commandLine, vmParameters, commandLineWrapper);
dynamicParameters = setCommandLineWrapperParams(javaParameters, commandLine, vmParameters, commandLineWrapper);
}
}
else {
@@ -202,7 +201,7 @@ public class JdkUtil {
throw new CantRunException(ExecutionBundle.message("main.class.is.not.specified.error.message"));
}
if (!passProgramParametersViaClassPathJar) {
if (!dynamicParameters) {
commandLine.addParameters(javaParameters.getProgramParametersList().getList());
}
@@ -217,14 +216,17 @@ public class JdkUtil {
return vmParameters.hasParameter("-p") || vmParameters.hasParameter("--module-path");
}
private static void appendOldCommandLineWrapper(SimpleJavaParameters javaParameters,
GeneralCommandLine commandLine,
ParametersList vmParametersList,
Class commandLineWrapper) throws CantRunException {
private static boolean setCommandLineWrapperParams(SimpleJavaParameters javaParameters,
GeneralCommandLine commandLine,
ParametersList vmParametersList,
Class commandLineWrapper) throws CantRunException {
boolean dynamicVMOptions = javaParameters.isDynamicVMOptions() && useDynamicVMOptions();
boolean dynamicParameters = javaParameters.isDynamicParameters() && useDynamicParameters();
File vmParamsFile = null;
if (javaParameters.isDynamicVMOptions() && useDynamicVMOptions()) {
if (dynamicVMOptions) {
try {
vmParamsFile = FileUtil.createTempFile("vm_params", null);
vmParamsFile = FileUtil.createTempFile("idea_vm_params", null);
try (PrintWriter writer = new PrintWriter(vmParamsFile)) {
for (String param : vmParametersList.getList()) {
if (param.startsWith("-D")) {
@@ -244,18 +246,29 @@ public class JdkUtil {
commandLine.addParameters(vmParametersList.getList());
}
File appParamsFile = null;
if (dynamicParameters) {
try {
appParamsFile = FileUtil.createTempFile("idea_app_params", null);
try (PrintWriter writer = new PrintWriter(appParamsFile)) {
for (String path : javaParameters.getProgramParametersList().getList()) {
writer.println(path);
}
}
}
catch (IOException e) {
throwUnableToCreateTempFile(e);
}
}
File classpathFile = null;
try {
classpathFile = FileUtil.createTempFile("classpath", null);
final PrintWriter writer = new PrintWriter(classpathFile);
try {
classpathFile = FileUtil.createTempFile("idea_classpath", null);
try (PrintWriter writer = new PrintWriter(classpathFile)) {
for (String path : javaParameters.getClassPath().getPathList()) {
writer.println(path);
}
}
finally {
writer.close();
}
String classpath = PathUtil.getJarPathForClass(commandLineWrapper);
final String utilRtPath = PathUtil.getJarPathForClass(StringUtilRt.class);
@@ -284,39 +297,47 @@ public class JdkUtil {
commandLine.addParameter(vmParamsFile.getAbsolutePath());
}
final Set<File> filesToDelete = getFilesToDeleteUserData(commandLine);
if (appParamsFile != null) {
commandLine.addParameter("@app_params");
commandLine.addParameter(appParamsFile.getAbsolutePath());
}
Set<File> filesToDelete = getFilesToDeleteUserData(commandLine);
ContainerUtil.addIfNotNull(filesToDelete, classpathFile);
ContainerUtil.addIfNotNull(filesToDelete, vmParamsFile);
ContainerUtil.addIfNotNull(filesToDelete, appParamsFile);
return dynamicParameters;
}
private static void appendJarClasspathParams(SimpleJavaParameters javaParameters,
private static boolean setClasspathJarParams(SimpleJavaParameters javaParameters,
GeneralCommandLine commandLine,
ParametersList vmParametersList,
Class commandLineWrapper,
boolean storeProgramParametersInJar) throws CantRunException {
Class commandLineWrapper) throws CantRunException {
boolean dynamicVMOptions = javaParameters.isDynamicVMOptions() && useDynamicVMOptions();
boolean dynamicParameters = javaParameters.isDynamicParameters() && useDynamicParameters();
try {
final Manifest manifest = new Manifest();
manifest.getMainAttributes().putValue("Created-By", ApplicationNamesInfo.getInstance().getFullProductName());
final boolean writeDynamicVMOptions = javaParameters.isDynamicVMOptions() && useDynamicVMOptions();
if (writeDynamicVMOptions) {
List<String> dParams = new ArrayList<>();
if (dynamicVMOptions) {
List<String> properties = new ArrayList<>();
for (String param : vmParametersList.getList()) {
if (param.startsWith("-D")) {
dParams.add(param);
properties.add(param);
}
else {
commandLine.addParameter(param);
}
}
manifest.getMainAttributes().putValue("VM-Options", ParametersListUtil.join(dParams));
manifest.getMainAttributes().putValue("VM-Options", ParametersListUtil.join(properties));
}
else {
commandLine.addParameters(vmParametersList.getList());
}
if (storeProgramParametersInJar) {
if (dynamicParameters) {
manifest.getMainAttributes().putValue("Program-Parameters", ParametersListUtil.join(javaParameters.getProgramParametersList().getList()));
}
@@ -328,7 +349,7 @@ public class JdkUtil {
final String jarFile = classpathJarFile.getAbsolutePath();
commandLine.addParameter("-classpath");
if (writeDynamicVMOptions || storeProgramParametersInJar) {
if (dynamicVMOptions || dynamicParameters) {
commandLine.addParameter(PathUtil.getJarPathForClass(commandLineWrapper) + File.pathSeparator + jarFile);
appendEncoding(javaParameters, commandLine, vmParametersList);
commandLine.addParameter(commandLineWrapper.getName());
@@ -342,6 +363,8 @@ public class JdkUtil {
catch (IOException e) {
throwUnableToCreateTempFile(e);
}
return dynamicParameters;
}
private static void throwUnableToCreateTempFile(IOException cause) throws CantRunException {
@@ -439,7 +462,11 @@ public class JdkUtil {
}
public static boolean useDynamicVMOptions() {
return PropertiesComponent.getInstance().getBoolean("dynamic.vmoptions", true);
return PropertiesComponent.getInstance().getBoolean("idea.dynamic.vmoptions", true);
}
public static boolean useDynamicParameters() {
return PropertiesComponent.getInstance().getBoolean("idea.dynamic.parameters", true);
}
public static boolean useClasspathJar() {