diff --git a/images/src/org/intellij/images/actions/EditExternallyAction.java b/images/src/org/intellij/images/actions/EditExternallyAction.java
index 2273bb65830a..57bf0d018ad2 100644
--- a/images/src/org/intellij/images/actions/EditExternallyAction.java
+++ b/images/src/org/intellij/images/actions/EditExternallyAction.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2011 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -87,7 +87,7 @@ public final class EditExternallyAction extends AnAction {
commandLine.addParameter(VfsUtil.virtualToIoFile(file).getAbsolutePath());
}
}
- commandLine.setWorkingDirectory(new File(executablePath).getParentFile());
+ commandLine.setWorkDirectory(new File(executablePath).getParentFile());
try {
commandLine.createProcess();
diff --git a/java/java-impl/src/com/intellij/javadoc/JavadocConfiguration.java b/java/java-impl/src/com/intellij/javadoc/JavadocConfiguration.java
index 59a0d7b4632e..4913ac98998d 100644
--- a/java/java-impl/src/com/intellij/javadoc/JavadocConfiguration.java
+++ b/java/java-impl/src/com/intellij/javadoc/JavadocConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2011 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -164,7 +164,7 @@ public class JavadocConfiguration implements ModuleRunProfile, JDOMExternalizabl
cmdLine.getParametersList().prepend("-J-mx" + HEAP_SIZE + "m");
}
}
- cmdLine.setWorkingDirectory(null);
+ cmdLine.setWorkDirectory((File)null);
@NonNls final String javadocExecutableName = File.separator + (SystemInfo.isWindows ? "javadoc.exe" : "javadoc");
@NonNls String exePath = jdkPath.replace('/', File.separatorChar) + javadocExecutableName;
if (new File(exePath).exists()) {
@@ -250,10 +250,9 @@ public class JavadocConfiguration implements ModuleRunProfile, JDOMExternalizabl
}
try {
- File sourcepathTempFile = FileUtil.createTempFile("javadoc", "args.txt");
- sourcepathTempFile.deleteOnExit();
- parameters.add("@" + sourcepathTempFile.getCanonicalPath());
- final PrintWriter writer = new PrintWriter(new FileWriter(sourcepathTempFile));
+ final File sourcePathTempFile = FileUtil.createTempFile("javadoc", "args.txt", true);
+ parameters.add("@" + sourcePathTempFile.getCanonicalPath());
+ final PrintWriter writer = new PrintWriter(new FileWriter(sourcePathTempFile));
try {
final Collection packages = new HashSet();
final Collection sources = new HashSet();
@@ -290,7 +289,7 @@ public class JavadocConfiguration implements ModuleRunProfile, JDOMExternalizabl
}
sourcePath.append(file.getPath());
}
- writer.println(GeneralCommandLine.quote(sourcePath.toString()));
+ writer.println(sourcePath.toString());
}
finally {
writer.close();
@@ -340,7 +339,7 @@ public class JavadocConfiguration implements ModuleRunProfile, JDOMExternalizabl
final PsiJavaFile javaFile = (PsiJavaFile)file;
final String packageName = javaFile.getPackageName();
if (containsPackagePrefix(module, packageName) || (packageName.length() == 0 && !(javaFile instanceof JspFile))) {
- mySourceFiles.add(GeneralCommandLine.quote(FileUtil.toSystemIndependentName(fileOrDir.getPath())));
+ mySourceFiles.add(FileUtil.toSystemIndependentName(fileOrDir.getPath()));
}
else {
myPackages.add(packageName);
diff --git a/java/java-tests/java-tests.iml b/java/java-tests/java-tests.iml
index a2196312e368..e2708d77ad84 100644
--- a/java/java-tests/java-tests.iml
+++ b/java/java-tests/java-tests.iml
@@ -25,6 +25,7 @@
+
diff --git a/java/java-tests/testSrc/com/intellij/execution/configurations/JavaCommandLineTest.java b/java/java-tests/testSrc/com/intellij/execution/configurations/JavaCommandLineTest.java
new file mode 100644
index 000000000000..2708ac91181c
--- /dev/null
+++ b/java/java-tests/testSrc/com/intellij/execution/configurations/JavaCommandLineTest.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2000-2011 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.execution.configurations;
+
+import com.intellij.execution.CantRunException;
+import com.intellij.execution.ExecutionBundle;
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.process.DefaultJavaProcessHandler;
+import com.intellij.ide.IdeBundle;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl;
+import com.intellij.testFramework.LightIdeaTestCase;
+import junit.framework.Assert;
+
+public class JavaCommandLineTest extends LightIdeaTestCase {
+ public void testJdk() {
+ try {
+ CommandLineBuilder.createFromJavaParameters(new JavaParameters());
+ fail("CantRunException (main class is not specified) expected");
+ }
+ catch (CantRunException e) {
+ Assert.assertEquals(ExecutionBundle.message("run.configuration.error.no.jdk.specified"), e.getMessage());
+ }
+ }
+
+ public void testMainClass() {
+ try {
+ JavaParameters javaParameters = new JavaParameters();
+ javaParameters.setJdk(getProjectJDK());
+ CommandLineBuilder.createFromJavaParameters(javaParameters);
+ fail("CantRunException (main class is not specified) expected");
+ }
+ catch (CantRunException e) {
+ assertEquals(ExecutionBundle.message("main.class.is.not.specified.error.message"), e.getMessage());
+ }
+ }
+
+ public void testClasspath() throws CantRunException {
+ JavaParameters javaParameters;
+ String commandLineString;
+
+ javaParameters = new JavaParameters();
+ final Sdk internalJdk = JavaAwareProjectJdkTableImpl.getInstanceEx().getInternalJdk();
+ javaParameters.setJdk(internalJdk);
+ javaParameters.setMainClass("Main");
+ commandLineString = CommandLineBuilder.createFromJavaParameters(javaParameters).getCommandLineString();
+ assertTrue(containsClassPath(commandLineString));
+
+ javaParameters = new JavaParameters();
+ javaParameters.setJdk(internalJdk);
+ javaParameters.setMainClass("Main");
+ javaParameters.getVMParametersList().add("-cp");
+ javaParameters.getVMParametersList().add("..");
+ commandLineString = CommandLineBuilder.createFromJavaParameters(javaParameters).getCommandLineString();
+ commandLineString = removeClassPath(commandLineString, "-cp ..");
+ assertTrue(!containsClassPath(commandLineString));
+
+ javaParameters = new JavaParameters();
+ javaParameters.setJdk(internalJdk);
+ javaParameters.setMainClass("Main");
+ javaParameters.getVMParametersList().add("-classpath");
+ javaParameters.getVMParametersList().add("..");
+ commandLineString = CommandLineBuilder.createFromJavaParameters(javaParameters).getCommandLineString();
+ commandLineString = removeClassPath(commandLineString, "-classpath ..");
+ assertTrue(!containsClassPath(commandLineString));
+ }
+
+ private static boolean containsClassPath(String commandLineString) {
+ return commandLineString.contains("-cp") || commandLineString.contains("-classpath");
+ }
+
+ private static String removeClassPath(String commandLineString, String pathString) {
+ int i = commandLineString.indexOf(pathString);
+ commandLineString = commandLineString.substring(0, i) + commandLineString.substring(i + pathString.length());
+ return commandLineString;
+ }
+
+ public void testCreateProcess() {
+ try {
+ new DefaultJavaProcessHandler(new GeneralCommandLine());
+ fail("ExecutionException (executable is not specified) expected");
+ }
+ catch (ExecutionException e) {
+ assertEquals(IdeBundle.message("run.configuration.error.executable.not.specified"), e.getMessage());
+ }
+ }
+}
diff --git a/java/java-tests/testSrc/com/intellij/execution/configurations/JavaParametersTest.java b/java/java-tests/testSrc/com/intellij/execution/configurations/JavaParametersTest.java
new file mode 100644
index 000000000000..9d1007f1bc1f
--- /dev/null
+++ b/java/java-tests/testSrc/com/intellij/execution/configurations/JavaParametersTest.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2000-2011 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.execution.configurations;
+
+import com.intellij.execution.CantRunException;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.DependencyScope;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.roots.ModuleRootManagerTestCase;
+
+/**
+ * @author nik
+ */
+public class JavaParametersTest extends ModuleRootManagerTestCase {
+ public void testLibrary() throws Exception {
+ addLibraryDependency(myModule, createJDomLibrary());
+ assertClasspath(myModule, JavaParameters.JDK_AND_CLASSES_AND_TESTS,
+ getRtJar(), getJDomJar());
+ assertClasspath(myModule, JavaParameters.CLASSES_ONLY,
+ getJDomJar());
+ assertClasspath(myModule, JavaParameters.CLASSES_AND_TESTS,
+ getJDomJar());
+ assertClasspath(myProject, JavaParameters.JDK_AND_CLASSES_AND_TESTS,
+ getRtJar(), getJDomJar());
+ }
+
+ public void testModuleSourcesAndOutput() throws Exception {
+ addSourceRoot(myModule, false);
+ addSourceRoot(myModule, true);
+ final VirtualFile output = setModuleOutput(myModule, false);
+ final VirtualFile testOutput = setModuleOutput(myModule, true);
+
+ assertClasspath(myModule, JavaParameters.CLASSES_ONLY,
+ output);
+ assertClasspath(myModule, JavaParameters.CLASSES_AND_TESTS,
+ testOutput, output);
+ assertClasspath(myModule, JavaParameters.JDK_AND_CLASSES_AND_TESTS,
+ getRtJar(), testOutput, output);
+ }
+
+ public void testLibraryScope() throws Exception {
+ addLibraryDependency(myModule, createJDomLibrary(), DependencyScope.RUNTIME, false);
+ addLibraryDependency(myModule, createAsmLibrary(), DependencyScope.TEST, false);
+
+ assertClasspath(myModule, JavaParameters.CLASSES_AND_TESTS,
+ getJDomJar(), getAsmJar());
+ assertClasspath(myModule, JavaParameters.CLASSES_ONLY,
+ getJDomJar());
+ }
+
+ public void testProvidedScope() throws Exception {
+ addLibraryDependency(myModule, createJDomLibrary(), DependencyScope.PROVIDED, false);
+
+ assertClasspath(myModule, JavaParameters.CLASSES_AND_TESTS, getJDomJar());
+ assertClasspath(myModule, JavaParameters.CLASSES_ONLY);
+ }
+
+ public void testModuleDependency() throws Exception {
+ final Module dep = createModule("dep");
+ final VirtualFile depOutput = setModuleOutput(dep, false);
+ final VirtualFile depTestOutput = setModuleOutput(dep, true);
+ addLibraryDependency(dep, createJDomLibrary());
+ addModuleDependency(myModule, dep);
+
+ assertClasspath(myModule, JavaParameters.CLASSES_ONLY,
+ depOutput, getJDomJar());
+ assertClasspath(myModule, JavaParameters.CLASSES_AND_TESTS,
+ depTestOutput, depOutput, getJDomJar());
+ }
+
+ public void testModuleDependencyScope() throws Exception {
+ final Module dep = createModule("dep");
+ addLibraryDependency(dep, createJDomLibrary());
+ addModuleDependency(myModule, dep, DependencyScope.TEST, true);
+
+ assertClasspath(myModule, JavaParameters.CLASSES_ONLY);
+ assertClasspath(myModule, JavaParameters.CLASSES_AND_TESTS,
+ getJDomJar());
+
+ assertClasspath(myProject, JavaParameters.CLASSES_ONLY,
+ getJDomJar());
+ }
+
+ private static void assertClasspath(final Module module, final int type, VirtualFile... roots) throws CantRunException {
+ final JavaParameters javaParameters = new JavaParameters();
+ javaParameters.configureByModule(module, type);
+ assertRoots(javaParameters.getClassPath(), roots);
+ }
+
+ private void assertClasspath(final Project project, final int type, VirtualFile... roots) throws CantRunException {
+ final JavaParameters javaParameters = new JavaParameters();
+ javaParameters.configureByProject(project, type, getTestProjectJdk());
+ assertRoots(javaParameters.getClassPath(), roots);
+ }
+}
diff --git a/platform/lang-impl/src/com/intellij/codeInspection/AbstractInspectionToolStarter.java b/platform/lang-impl/src/com/intellij/codeInspection/AbstractInspectionToolStarter.java
index 7a522b306b7e..9e3bf6e4c513 100644
--- a/platform/lang-impl/src/com/intellij/codeInspection/AbstractInspectionToolStarter.java
+++ b/platform/lang-impl/src/com/intellij/codeInspection/AbstractInspectionToolStarter.java
@@ -1,13 +1,30 @@
+/*
+ * Copyright 2000-2011 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package com.intellij.codeInspection;
-import com.intellij.execution.configurations.GeneralCommandLine;
+import com.intellij.execution.configurations.ParametersList;
import com.intellij.openapi.application.ApplicationStarter;
+import com.intellij.util.containers.CollectionFactory;
import com.sampullara.cli.Args;
import org.jetbrains.annotations.NotNull;
/**
* @author Roman.Chernyatchik
*/
+@SuppressWarnings("UseOfSystemOutOrSystemErr")
public abstract class AbstractInspectionToolStarter implements ApplicationStarter {
protected InspectionApplication myApplication;
protected InspectionToolCmdlineOptions myOptions;
@@ -19,7 +36,8 @@ public abstract class AbstractInspectionToolStarter implements ApplicationStarte
myOptions = createCmdlineOptions();
try {
Args.parse(myOptions, args);
- } catch (Exception e) {
+ }
+ catch (Exception e) {
printHelpAndExit(args, myOptions);
return;
}
@@ -32,17 +50,18 @@ public abstract class AbstractInspectionToolStarter implements ApplicationStarte
}
// TODO[romeo] : if config given - parse config and set attrs
- //Properties p = new Properties();
- // p.put("input", "inputfile");
- // p.put("o", "outputfile");
- // p.put("someflag", "true");
- // p.put("m", "10");
- // p.put("values", "1:2:3");
- // p.put("strings", "sam;dave;jolly");
- // PropertiesArgs.parse(tc, p);
- try{
+ //Properties p = new Properties();
+ // p.put("input", "inputfile");
+ // p.put("o", "outputfile");
+ // p.put("someflag", "true");
+ // p.put("m", "10");
+ // p.put("values", "1:2:3");
+ // p.put("strings", "sam;dave;jolly");
+ // PropertiesArgs.parse(tc, p);
+ try {
myOptions.validate();
- } catch (InspectionToolCmdlineOptions.CmdlineArgsValidationException e) {
+ }
+ catch (InspectionToolCmdlineOptions.CmdlineArgsValidationException e) {
System.err.println(e.getMessage());
if (!myOptions.suppressHelp()) {
printHelpAndExit(args, myOptions);
@@ -66,23 +85,22 @@ public abstract class AbstractInspectionToolStarter implements ApplicationStarte
myApplication.startup();
}
- private void initApplication(@NotNull final InspectionApplication application,
- @NotNull final InspectionToolCmdlineOptions opts) {
+ private static void initApplication(@NotNull final InspectionApplication application,
+ @NotNull final InspectionToolCmdlineOptions opts) {
opts.initApplication(application);
}
- private boolean verbose(final InspectionToolCmdlineOptions opts) {
+ private static boolean verbose(final InspectionToolCmdlineOptions opts) {
return opts.getVerboseLevelProperty() > 0;
}
protected void printArgs(String[] args, StringBuilder buff) {
if (args.length < 2) {
buff.append(" no arguments");
- } else {
- for (int i = 1, argsLength = args.length; i < argsLength; i++) {
- String arg = args[i];
- buff.append(' ').append(GeneralCommandLine.quote(arg));
- }
+ }
+ else {
+ final String argString = ParametersList.join(CollectionFactory.arrayList(args, 1, args.length));
+ buff.append(argString);
}
}
diff --git a/platform/platform-api/src/com/intellij/execution/configurations/GeneralCommandLine.java b/platform/platform-api/src/com/intellij/execution/configurations/GeneralCommandLine.java
index 1672e82b9946..bdcbdbf5964e 100644
--- a/platform/platform-api/src/com/intellij/execution/configurations/GeneralCommandLine.java
+++ b/platform/platform-api/src/com/intellij/execution/configurations/GeneralCommandLine.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2011 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,12 +18,10 @@ package com.intellij.execution.configurations;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.process.ProcessNotCreatedException;
import com.intellij.ide.IdeBundle;
-import com.intellij.openapi.diagnostic.Log;
-import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.CharsetToolkit;
-import com.intellij.util.containers.HashMap;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -31,45 +29,65 @@ import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
-import java.util.Iterator;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+/**
+ * OS-independent way of executing external processes with complex parameters.
+ *
+ * Main idea of the class is to accept parameters "as-is", just as they should look to an external process, and quote/escape them
+ * as required by the underlying platform.
+ *
+ * todo: check help
+ */
public class GeneralCommandLine {
- private static final Logger LOG = Logger.getInstance("#" + GeneralCommandLine.class.getName());
- private Map myEnvParams;
- private boolean myPassParentEnvs;
private String myExePath = null;
private File myWorkDirectory = null;
- private ParametersList myProgramParams = new ParametersList();
+ private Map myEnvParams = null;
+ private boolean myPassParentEnvironment = true;
+ private final ParametersList myProgramParams = new ParametersList();
private Charset myCharset = CharsetToolkit.getDefaultSystemCharset();
-
- public void setExePath(@NonNls final String exePath) {
- myExePath = exePath.trim();
- }
+ private boolean myRedirectErrorStream = false;
public String getExePath() {
return myExePath;
}
- public void setWorkDirectory(@NonNls final String path) {
- setWorkingDirectory(path != null? new File(path) : null);
- }
-
- public void setWorkingDirectory(final File workingDirectory) {
- myWorkDirectory = workingDirectory;
+ public void setExePath(@NotNull @NonNls final String exePath) {
+ myExePath = exePath.trim();
}
public File getWorkDirectory() {
return myWorkDirectory;
}
- public void setEnvParams(final Map envParams) {
+ public void setWorkDirectory(@Nullable @NonNls final String path) {
+ setWorkDirectory(path != null ? new File(path) : null);
+ }
+
+ public void setWorkDirectory(@Nullable final File workDirectory) {
+ myWorkDirectory = workDirectory;
+ }
+
+ /**
+ * @deprecated use {@link #setWorkDirectory(java.io.File)} (to remove in IDEA 12).
+ */
+ public void setWorkingDirectory(@Nullable final File workDirectory) {
+ setWorkDirectory(workDirectory);
+ }
+
+ @Nullable
+ public Map getEnvParams() {
+ return myEnvParams;
+ }
+
+ public void setEnvParams(@Nullable final Map envParams) {
myEnvParams = envParams;
}
- public void setCharset(@NotNull Charset charset) {
- myCharset = charset;
+ public void setPassParentEnvs(final boolean passParentEnvironment) {
+ myPassParentEnvironment = passParentEnvironment;
}
public void addParameters(final String... parameters) {
@@ -78,7 +96,7 @@ public class GeneralCommandLine {
}
}
- public void addParameters(final List parameters) {
+ public void addParameters(@NotNull final List parameters) {
for (final String parameter : parameters) {
addParameter(parameter);
}
@@ -88,37 +106,105 @@ public class GeneralCommandLine {
myProgramParams.add(parameter);
}
- public String getCommandLineString() {
- final StringBuffer buffer = new StringBuffer(quoteParameter(FileUtil.toSystemDependentName(myExePath)));
- appendParams( buffer );
- return buffer.toString();
- }
-
- public String getCommandLineParams() {
- final StringBuffer buffer = new StringBuffer();
- appendParams( buffer );
- return buffer.toString();
- }
-
- private void appendParams( StringBuffer buffer ) {
- for( final String param : myProgramParams.getList() ) {
- buffer.append(" ").append(quoteParameter(param));
- }
+ public ParametersList getParametersList() {
+ return myProgramParams;
}
+ @NotNull
public Charset getCharset() {
return myCharset;
}
+ public void setCharset(@NotNull final Charset charset) {
+ myCharset = charset;
+ }
+
+ public void setRedirectErrorStream(final boolean redirectErrorStream) {
+ myRedirectErrorStream = redirectErrorStream;
+ }
+
+ /**
+ * @deprecated please use {@link #getCommandLineString()} (to remove in IDEA 12).
+ */
+ @SuppressWarnings("UnusedDeclaration")
+ public String getCommandLineParams() {
+ return getCommandLineString();
+ }
+
+ /**
+ * Returns string representation of this command line.
+ * Warning: resulting string is not OS-dependent - do not use it for executing this command line.
+ *
+ * @return single-string representation of this command line.
+ */
+ public String getCommandLineString() {
+ return getCommandLineString(null);
+ }
+
+ /**
+ * Returns string representation of this command line.
+ * Warning: resulting string is not OS-dependent - do not use it for executing this command line.
+ *
+ * @param exeName use this executable name instead of given by {@link #setExePath(String)}
+ * @return single-string representation of this command line.
+ */
+ public String getCommandLineString(@Nullable final String exeName) {
+ final List commands = new ArrayList();
+ if (exeName != null) {
+ commands.add(exeName);
+ }
+ else if (myExePath != null) {
+ commands.add(FileUtil.toSystemDependentName(myExePath));
+ }
+ else {
+ commands.add("");
+ }
+ commands.addAll(myProgramParams.getList());
+ return ParametersList.join(commands);
+ }
+
+ /**
+ * Returns a list of command and its parameters prepared in OS-dependent way to be executed by e.g. {@link Runtime#exec(String[])}.
+ *
+ * @deprecated this method is not intended for internal use (to remove in IDEA 12).
+ */
+ public String[] getCommands() {
+ return prepareCommands();
+ }
+
+ /**
+ * @deprecated use {@link #addParameter(String)} and {@link #addParameters(String...)} methods for adding parameters -
+ * any quoting needed will be done on {@link #createProcess()} (to remove in IDEA 12).
+ */
+ @SuppressWarnings("UnusedDeclaration")
+ public static String quoteParameter(final String parameter) {
+ return parameter;
+ }
+
+ /**
+ * @deprecated use {@link #addParameter(String)} and {@link #addParameters(String...)} methods for adding parameters -
+ * any quoting needed will be done on {@link #createProcess()} (to remove in IDEA 12).
+ */
+ @SuppressWarnings("UnusedDeclaration")
+ public static String quote(final String parameter) {
+ return parameter;
+ }
+
public Process createProcess() throws ExecutionException {
checkWorkingDirectory();
- try {
- final String[] commands = getCommands();
- if(commands[0] == null) throw new ExecutionException(IdeBundle.message("run.configuration.error.executable.not.specified"));
- return myWorkDirectory != null
- ? Runtime.getRuntime().exec(commands, getEnvParamsArray(), myWorkDirectory)
- : Runtime.getRuntime().exec(commands, getEnvParamsArray());
+ final String[] commands = prepareCommands();
+ if (StringUtil.isEmptyOrSpaces(commands[0])) {
+ throw new ExecutionException(IdeBundle.message("run.configuration.error.executable.not.specified"));
+ }
+
+ try {
+ final ProcessBuilder builder = new ProcessBuilder(commands);
+ final Map environment = builder.environment();
+ setupEnvironment(environment);
+ builder.directory(myWorkDirectory);
+ builder.redirectErrorStream(myRedirectErrorStream);
+ return builder.start();
}
catch (IOException e) {
throw new ProcessNotCreatedException(e.getMessage(), e, this);
@@ -138,98 +224,33 @@ public class GeneralCommandLine {
}
}
- @Nullable
- public Map getEnvParams() {
- return myEnvParams;
- }
-
- @Nullable
- private String[] getEnvParamsArray() {
- final Map envParams = collectEnvParams();
- if (envParams == null) return null;
- for (Iterator iterator = envParams.keySet().iterator(); iterator.hasNext(); ) {
- final String key = iterator.next();
- if (envParams.get(key) == null) {
- LOG.info("null value for env variable: " + key);
- iterator.remove();
- }
- }
- final String[] result = new String[envParams.size()];
- int i=0;
- for (final String key : envParams.keySet()) {
- result[i++] = key + "=" + envParams.get(key).trim();
- }
- return result;
- }
-
- @Nullable
- private Map collectEnvParams() {
- if (myEnvParams == null) {
- return null;
- }
- final Map envParams = new HashMap();
- if (myPassParentEnvs) {
- envParams.putAll(System.getenv());
- }
- envParams.putAll(myEnvParams);
- return envParams;
- }
-
- public String[] getCommands() {
+ private String[] prepareCommands() {
final List parameters = myProgramParams.getList();
final String[] result = new String[parameters.size() + 1];
- result[0] = myExePath;
- int index = 1;
- for (Iterator iterator = parameters.iterator(); iterator.hasNext(); index++) {
- result[index] = iterator.next();
+ result[0] = prepareCommand(myExePath != null ? FileUtil.toSystemDependentName(myExePath) : null);
+ for (int i = 0; i < parameters.size(); i++) {
+ result[i + 1] = prepareCommand(parameters.get(i));
}
return result;
}
- public ParametersList getParametersList() {
- return myProgramParams;
- }
-
- public static String quoteParameter(final String param) {
- if (!SystemInfo.isWindows) {
- return param;
- }
- return quote(param);
- }
-
- public static String quote(final String parameter) {
- if (parameter == null || !hasWhitespace(parameter)) {
- return parameter; // no need to quote
- }
- if (parameter.length() >= 2 && parameter.startsWith("\"") && parameter.endsWith("\"")) {
- return parameter; // already quoted
- }
- // need to escape trailing slash if any, otherwise it will escape the ending quote
- return "\"" + parameter + (parameter.endsWith("\\")? "\\\"" : "\"");
- }
-
- private static boolean hasWhitespace(final String string) {
- final int length = string.length();
- for (int i = 0; i < length; i++) {
- if (Character.isWhitespace(string.charAt(i))) {
- return true;
+ private static String prepareCommand(String parameter) {
+ // AFAIK, the only thing needed is escaping double quotes on Windows
+ if (SystemInfo.isWindows) {
+ if (parameter.contains("\"")) {
+ parameter = StringUtil.replace(parameter, "\"", "\\\"");
}
}
- return false;
+ return parameter;
}
- public GeneralCommandLine clone() {
- final GeneralCommandLine clone = new GeneralCommandLine();
- clone.myCharset = myCharset;
- clone.myExePath = myExePath;
- clone.myWorkDirectory = myWorkDirectory;
- clone.myProgramParams = myProgramParams.clone();
- clone.myEnvParams = myEnvParams != null ? new HashMap(myEnvParams) : null;
- return clone;
- }
-
- public void setPassParentEnvs(final boolean passParentEnvs) {
- myPassParentEnvs = passParentEnvs;
+ private void setupEnvironment(final Map environment) {
+ if (!myPassParentEnvironment) {
+ environment.clear();
+ }
+ if (myEnvParams != null) {
+ environment.putAll(myEnvParams);
+ }
}
@Override
diff --git a/platform/platform-api/src/com/intellij/execution/configurations/ParametersList.java b/platform/platform-api/src/com/intellij/execution/configurations/ParametersList.java
index 088c0af8ef7c..6735bbbc86a4 100644
--- a/platform/platform-api/src/com/intellij/execution/configurations/ParametersList.java
+++ b/platform/platform-api/src/com/intellij/execution/configurations/ParametersList.java
@@ -22,6 +22,8 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.EnvironmentUtil;
+import com.intellij.util.StringBuilderSpinAllocator;
+import com.intellij.util.containers.CollectionFactory;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -29,8 +31,9 @@ import org.jetbrains.annotations.Nullable;
import java.util.*;
-public class ParametersList implements Cloneable{
+public class ParametersList implements Cloneable {
private static final Logger LOG = Logger.getInstance("#com.intellij.execution.configurations.ParametersList");
+
private List myParameters = new ArrayList();
private Map myMacroMap = null;
private List myGroups = new ArrayList();
@@ -47,9 +50,9 @@ public class ParametersList implements Cloneable{
}
@Nullable
- public String getPropertyValue(@NonNls final String name) {
+ public String getPropertyValue(@NotNull @NonNls final String name) {
+ final String prefix = "-D" + name + "=";
for (String parameter : myParameters) {
- @NonNls String prefix = "-D" + name + "=";
if (parameter.startsWith(prefix)) {
return parameter.substring(prefix.length());
}
@@ -57,29 +60,39 @@ public class ParametersList implements Cloneable{
return null;
}
+ @NotNull
public String getParametersString() {
- final StringBuilder buffer = new StringBuilder();
- final String separator = " ";
- for (final String param : myParameters) {
- buffer.append(separator);
- buffer.append(GeneralCommandLine.quote(param));
- }
- for (ParamsGroup paramsGroup : myGroups) {
- // params group parameters string already contains a separator
- buffer.append(paramsGroup.getParametersList().getParametersString());
- }
- return buffer.toString();
+ return join(getList());
}
+ @NotNull
public String[] getArray() {
return ArrayUtil.toStringArray(getList());
}
+ @NotNull
+ public List getList() {
+ if (myGroups.isEmpty()) {
+ return Collections.unmodifiableList(myParameters);
+ }
+
+ final List params = new ArrayList();
+ params.addAll(myParameters);
+ for (ParamsGroup group : myGroups) {
+ params.addAll(group.getParameters());
+ }
+ return Collections.unmodifiableList(params);
+ }
+
+ public void prepend(@NonNls final String parameter) {
+ addAt(0, parameter);
+ }
+
public void addParametersString(final String parameters) {
if (parameters != null) {
- final String[] parms = parse(parameters);
- for (String parm : parms) {
- add(parm);
+ final String[] split = parse(parameters);
+ for (String param : split) {
+ add(param);
}
}
}
@@ -97,14 +110,12 @@ public class ParametersList implements Cloneable{
return group;
}
- public ParamsGroup addParamsGroupAt(final int index,
- @NotNull final ParamsGroup group) {
+ public ParamsGroup addParamsGroupAt(final int index, @NotNull final ParamsGroup group) {
myGroups.add(index, group);
return group;
}
- public ParamsGroup addParamsGroupAt(final int index,
- @NotNull final String groupId) {
+ public ParamsGroup addParamsGroupAt(final int index, @NotNull final String groupId) {
final ParamsGroup group = new ParamsGroup(groupId);
myGroups.add(index, group);
return group;
@@ -173,33 +184,12 @@ public class ParametersList implements Cloneable{
replaceOrAdd(parameter, replacement, 0);
}
- public List getList() {
- if (myGroups.isEmpty()) {
- return Collections.unmodifiableList(myParameters);
- }
-
- final List params = new ArrayList();
-
- // params
- params.addAll(myParameters);
-
- // recursively add groups
- for (ParamsGroup group : myGroups) {
- params.addAll(group.getParameters());
- }
- return Collections.unmodifiableList(params);
- }
-
- public void prepend(@NonNls final String parameter) {
- addAt(0, parameter);
- }
-
- public void add(@NonNls final String name,@NonNls final String value) {
+ public void add(@NonNls final String name, @NonNls final String value) {
add(name);
add(value);
}
- public void addAll(final String[] parameters) {
+ public void addAll(final String... parameters) {
ContainerUtil.addAll(myParameters, parameters);
}
@@ -207,6 +197,7 @@ public class ParametersList implements Cloneable{
myParameters.addAll(parameters);
}
+ @Override
public ParametersList clone() {
try {
final ParametersList clone = (ParametersList)super.clone();
@@ -223,10 +214,66 @@ public class ParametersList implements Cloneable{
}
}
- public static String[] parse(final String string){
- return new ParametersTokenizer(string).execute();
+ /**
+ * Joins list of parameters into single string, which may be then parsed back into list by {@link #parse(String)}.
+ *
+ *
+ * Conversion rules:
+ *
+ * - double quotes are escaped by backslash (
\);
+ * - empty parameters parameters and parameters with spaces inside are surrounded with double quotes (
");
+ * - parameters are separated by single whitespace.
+ *
+ *
+ *
+ * Examples:
+ *
+ * ['a', 'b'] => 'a b'
+ * ['a="1 2"', 'b'] => '"a \"1 2\"" b'
+ *
+ *
+ * @param parameters a list of parameters to join.
+ * @return a string with parameters.
+ */
+ @NotNull
+ public static String join(@NotNull final List parameters) {
+ return ParametersTokenizer.encode(parameters);
}
+ @NotNull
+ public static String join(final String... parameters) {
+ return ParametersTokenizer.encode(Arrays.asList(parameters));
+ }
+
+ /**
+ * Converts single parameter string (as created by {@link #join(java.util.List)}) into list of parameters.
+ *
+ *
+ * Conversion rules:
+ *
+ * - starting/whitespaces are trimmed;
+ * - parameters are split by whitespaces, whitespaces itself are dropped
+ * - parameters inside double quotes (
"a b") are kept as single one;
+ * - double quotes are dropped, escaped double quotes (
\") are un-escaped.
+ *
+ *
+ *
+ * Examples:
+ *
+ * ' a b ' => ['a', 'b']
+ * 'a="1 2" b' => ['a=1 2', 'b']
+ * 'a " " b' => ['a', ' ', 'b']
+ * '"a \"1 2\"" b' => ['a="1 2"', 'b']
+ *
+ *
+ * @param string parameter string to split.
+ * @return array of parameters.
+ */
+ @NotNull
+ public static String[] parse(@NotNull final String string) {
+ final List params = ParametersTokenizer.decode(string);
+ return ArrayUtil.toStringArray(params);
+ }
public String expandMacros(String text) {
final Map macroMap = getMacroMap();
@@ -263,101 +310,88 @@ public class ParametersList implements Cloneable{
return myMacroMap;
}
- private static class ParametersTokenizer {
- private final String myParamsString;
- private final List myArray = new ArrayList();
- private final StringBuffer myBuffer = new StringBuffer(128);
- private boolean myTokenStarted = false;
- private boolean myUnquotedSlash = false;
- private boolean mySplittedQuotingStarted = false;
-
- public ParametersTokenizer(@NotNull final String parmsString) {
- myParamsString = parmsString;
- }
-
- public String[] execute() {
- boolean inQuotes = false;
-
- // \" sequence is turned to " inside ""
- boolean wasEscaped = false;
-
- for (int i = 0; i < myParamsString.length(); i++) {
- final char c = myParamsString.charAt(i);
-
- if (inQuotes) {
- LOG.assertTrue(!myUnquotedSlash);
- if (wasEscaped) {
- //if (c != '"') append('\\');
- append(c);
- wasEscaped = false;
- }
- else if (c == '"') {
- inQuotes = false;
- }
- else if (c == '\\') {
- myTokenStarted = true;
- append(c);
- wasEscaped = true;
- }
- else {
- append(c);
- }
- }
- else {
- inQuotes = processNotQuoted(c, myBuffer.length() == 0 || myBuffer.charAt(myBuffer.length() - 1) == ' ');
- }
- }
- tokenFinished();
- return ArrayUtil.toStringArray(myArray);
- }
-
- private boolean processNotQuoted(final char c, final boolean isPreviousSpace) {
- if (c == '"') {
- if (myUnquotedSlash) {
- append(c);
- myUnquotedSlash = false;
- return false;
- }
- else if (!isPreviousSpace || mySplittedQuotingStarted) {
- append(c);
- mySplittedQuotingStarted = !mySplittedQuotingStarted;
- return false;
- }
- myTokenStarted = true;
- return true;
- }
- else if (c == ' ') {
- tokenFinished();
- }
- else if (c == '\\') {
- myUnquotedSlash = true;
- append(c);
- return false;
- }
- else {
- append(c);
- }
- myUnquotedSlash = false;
- return false;
- }
-
- private void append(final char nextChar) {
- myBuffer.append(nextChar);
- myTokenStarted = true;
- }
-
- private void tokenFinished() {
- if (myTokenStarted) {
- final String token = myBuffer.length() == 0 ? "\"\"" : myBuffer.toString();
- myArray.add(token);
- }
- myBuffer.setLength(0);
- myTokenStarted = false;
- }
- }
-
@Override
public String toString() {
return myParameters.toString();
}
+
+ private static class ParametersTokenizer {
+ private ParametersTokenizer() { }
+
+ @NotNull
+ public static String encode(@NotNull final List parameters) {
+ final StringBuilder buffer = new StringBuilder();
+ for (final String parameter : parameters) {
+ if (buffer.length() > 0) {
+ buffer.append(' ');
+ }
+ buffer.append(encode(parameter));
+ }
+ return buffer.toString();
+ }
+
+ @NotNull
+ public static String encode(@NotNull String parameter) {
+ final StringBuilder builder = StringBuilderSpinAllocator.alloc();
+ try {
+ builder.append(parameter);
+ StringUtil.escapeQuotes(builder);
+ if (builder.length() == 0 || StringUtil.indexOf(builder, ' ') >= 0) {
+ StringUtil.quote(builder);
+ }
+ return builder.toString();
+ }
+ finally {
+ StringBuilderSpinAllocator.dispose(builder);
+ }
+ }
+
+ @NotNull
+ public static List decode(@NotNull String parameterString) {
+ parameterString = parameterString.trim();
+
+ final ArrayList params = CollectionFactory.arrayList();
+ final StringBuilder token = new StringBuilder(128);
+ boolean inQuotes = false;
+ boolean escapedQuote = false;
+ boolean nonEmpty = false;
+
+ for (int i = 0; i < parameterString.length(); i++) {
+ final char ch = parameterString.charAt(i);
+
+ if (ch == '\"') {
+ if (!escapedQuote) {
+ inQuotes = !inQuotes;
+ nonEmpty = true;
+ continue;
+ }
+ escapedQuote = false;
+ }
+ else if (Character.isWhitespace(ch)) {
+ if (!inQuotes) {
+ if (token.length() > 0 || nonEmpty) {
+ params.add(token.toString());
+ token.setLength(0);
+ nonEmpty = false;
+ }
+ continue;
+ }
+ }
+ else if (ch == '\\') {
+ if (i < parameterString.length() - 1 && parameterString.charAt(i + 1) == '"') {
+ escapedQuote = true;
+ continue;
+ }
+ }
+
+ token.append(ch);
+ }
+
+ if (token.length() > 0 || nonEmpty) {
+ params.add(token.toString());
+ }
+
+ return params;
+ }
+ }
}
diff --git a/platform/platform-api/src/com/intellij/execution/configurations/ParamsGroup.java b/platform/platform-api/src/com/intellij/execution/configurations/ParamsGroup.java
index b7ca25a54cb2..dd25946497d7 100644
--- a/platform/platform-api/src/com/intellij/execution/configurations/ParamsGroup.java
+++ b/platform/platform-api/src/com/intellij/execution/configurations/ParamsGroup.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2010 JetBrains s.r.o.
+ * Copyright 2000-2011 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,7 +31,7 @@ import java.util.List;
* different kinds of ruby tests, rails configuration, etc). Coverage support require to reorder args
* in cmdline, add rcov runner script, etc. Without groups it would be harder to parse abstract list of arguments
*/
-public class ParamsGroup implements Cloneable{
+public class ParamsGroup implements Cloneable {
private static final Logger LOG = Logger.getInstance(ParamsGroup.class.getName());
private String myGroupId;
@@ -73,6 +73,7 @@ public class ParamsGroup implements Cloneable{
return myGroupParams;
}
+ @Override
public ParamsGroup clone() {
try {
final ParamsGroup clone = (ParamsGroup)super.clone();
diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/external/BaseExternalTool.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/external/BaseExternalTool.java
index 9a4b0b55bbb1..ad2735f1cb89 100644
--- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/external/BaseExternalTool.java
+++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/external/BaseExternalTool.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2011 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -59,14 +59,14 @@ abstract class BaseExternalTool implements DiffTool {
}
public void show(DiffRequest request) {
- //ArrayList commandLine = new ArrayList();
GeneralCommandLine commandLine = new GeneralCommandLine();
commandLine.setExePath(getToolPath());
try {
commandLine.addParameter(convertToPath(request, 0));
commandLine.addParameter(convertToPath(request, 1));
- Runtime.getRuntime().exec(commandLine.getCommands());
- } catch (IOException e) {
+ commandLine.createProcess();
+ }
+ catch (Exception e) {
ExecutionErrorDialog.show(new ExecutionException(e.getMessage()),
DiffBundle.message("cant.launch.diff.tool.error.message"), request.getProject());
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/external/DiffManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/external/DiffManagerImpl.java
index 93709d2b8c96..d2c610ffb9e5 100644
--- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/external/DiffManagerImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/external/DiffManagerImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2011 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,7 +15,6 @@
*/
package com.intellij.openapi.diff.impl.external;
-import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.diff.DiffManager;
import com.intellij.openapi.diff.DiffPanel;
@@ -42,13 +41,15 @@ import java.util.Arrays;
public class DiffManagerImpl extends DiffManager implements JDOMExternalizable {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.diff.impl.external.DiffManagerImpl");
+
private static final Externalizer TOOL_PATH_UPDATE = new Externalizer() {
@NonNls private static final String NEW_VALUE = "newValue";
+
public String readValue(Element dataElement) {
String path = dataElement.getAttributeValue(NEW_VALUE);
if (path != null) return path;
String prevValue = dataElement.getAttributeValue(VALUE_ATTRIBUTE);
- return prevValue != null ? GeneralCommandLine.quote(prevValue.trim()) : null;
+ return prevValue != null ? prevValue.trim() : null;
}
public void writeValue(Element dataElement, String path) {
@@ -56,6 +57,7 @@ public class DiffManagerImpl extends DiffManager implements JDOMExternalizable {
dataElement.setAttribute(NEW_VALUE, path);
}
};
+
static final StringProperty FOLDERS_TOOL = new StringProperty("foldersTool", "");
static final StringProperty FILES_TOOL = new StringProperty("filesTool", "");
static final BooleanProperty ENABLE_FOLDERS = new BooleanProperty(
diff --git a/platform/platform-impl/testSrc/com/intellij/execution/EnvPassingTest.java b/platform/platform-impl/testSrc/com/intellij/execution/EnvPassingTest.java
new file mode 100644
index 000000000000..b53e701c92c5
--- /dev/null
+++ b/platform/platform-impl/testSrc/com/intellij/execution/EnvPassingTest.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2000-2011 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.execution;
+
+import java.util.Map;
+
+/**
+ * Invoked from {@link GeneralCommandLineTest} as external process.
+ */
+@SuppressWarnings("UtilityClassWithoutPrivateConstructor")
+public class EnvPassingTest {
+ public static void main(String[] args) {
+ final Map environment = System.getenv();
+ System.out.println("=====");
+ for (Map.Entry entry : environment.entrySet()) {
+ System.out.println(formatEntry(entry));
+ }
+ System.out.println("=====");
+ }
+
+ public static String formatEntry(final Map.Entry entry) {
+ return entry.getKey() + "=" + entry.getValue().hashCode();
+ }
+}
diff --git a/platform/platform-impl/testSrc/com/intellij/execution/GeneralCommandLineTest.java b/platform/platform-impl/testSrc/com/intellij/execution/GeneralCommandLineTest.java
new file mode 100644
index 000000000000..8b4e8b40275a
--- /dev/null
+++ b/platform/platform-impl/testSrc/com/intellij/execution/GeneralCommandLineTest.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2000-2011 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.execution;
+
+import com.intellij.execution.configurations.GeneralCommandLine;
+import com.intellij.openapi.util.SystemInfo;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.system.ExecUtil;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.testFramework.UsefulTestCase;
+
+import java.io.File;
+import java.net.URL;
+import java.util.*;
+
+public class GeneralCommandLineTest extends UsefulTestCase {
+ public void testPrintCommandLine() {
+ final GeneralCommandLine commandLine = new GeneralCommandLine();
+ commandLine.setExePath("e x e path");
+ commandLine.addParameter("with space");
+ commandLine.addParameter("\"quoted\"");
+ commandLine.addParameter("\"quoted with spaces\"");
+ commandLine.addParameters("param 1", "param2");
+ commandLine.addParameter("trailing slash\\");
+ assertEquals("\"e x e path\"" +
+ " \"with space\"" +
+ " \\\"quoted\\\"" +
+ " \"\\\"quoted with spaces\\\"\"" +
+ " \"param 1\"" +
+ " param2" +
+ " \"trailing slash\\\"",
+ commandLine.getCommandLineString());
+ }
+
+ public void testExecuteCommandLine() throws Exception {
+ final File tempFile;
+ if (SystemInfo.isWindows) {
+ final URL url = getClass().getClassLoader().getResource("com/intellij/execution/printArgs.exe");
+ assertNotNull(url);
+ tempFile = FileUtil.createTempFile("path with spaces 'and quotes' ", ".exe");
+ FileUtil.copy(new File(url.getFile()), tempFile);
+ }
+ else {
+ tempFile = ExecUtil.createTempExecutableScript(
+ "path with spaces \"and quotes\" ", ".sh",
+ "#!/bin/sh\n\n" +
+ "echo \"=====\"\n" +
+ "for f in \"$@\" ; do echo $f; done\n" +
+ "echo \"=====\"\n"
+ );
+ }
+
+ final String[] parameters = { "with space", "\"quoted\"", "\"quoted with spaces\"", "", "param 1", "\"", "param2", "trailing slash\\" };
+ try {
+ final GeneralCommandLine commandLine = new GeneralCommandLine();
+ commandLine.setExePath(tempFile.getCanonicalPath());
+ commandLine.addParameters(parameters);
+ commandLine.setRedirectErrorStream(true);
+ final Process process = commandLine.createProcess();
+ final String output = FileUtil.loadTextAndClose(process.getInputStream());
+ final int result = process.waitFor();
+
+ assertEquals("Command:\n" + commandLine.getCommandLineString() + "\nOutput:\n" + output,
+ 0, result);
+ assertEquals("=====\n" + StringUtil.join(parameters, "\n") + "\n=====\n",
+ StringUtil.convertLineSeparators(output));
+ }
+ finally {
+ FileUtil.delete(tempFile);
+ }
+ }
+
+ public void testEnvironmentPassing() throws Exception {
+ final URL url = getClass().getClassLoader().getResource("com/intellij/execution/EnvPassingTest.class");
+ assertNotNull(url);
+ final File testClass = new File(url.getFile());
+
+ final GeneralCommandLine commandLine = new GeneralCommandLine();
+ commandLine.setExePath("java");
+ commandLine.addParameter("-cp");
+ commandLine.addParameter(testClass.getParentFile().getParentFile().getParentFile().getParentFile().getAbsolutePath());
+ commandLine.addParameter("com.intellij.execution." + testClass.getName().replace(".class", ""));
+ commandLine.setRedirectErrorStream(true);
+
+ final Map testEnv = new HashMap();
+ testEnv.put("VALUE_1", "some value");
+ testEnv.put("VALUE_2", "another\n\"value\"");
+
+ checkEnvPassing(commandLine, testEnv, true);
+ checkEnvPassing(commandLine, testEnv, false);
+ }
+
+ private static void checkEnvPassing(final GeneralCommandLine commandLine,
+ final Map testEnv,
+ final boolean passParentEnv) throws Exception {
+ commandLine.setEnvParams(testEnv);
+ commandLine.setPassParentEnvs(passParentEnv);
+
+ final Process process = commandLine.createProcess();
+ final String output = FileUtil.loadTextAndClose(process.getInputStream());
+ final int result = process.waitFor();
+ assertEquals("Command:\n" + commandLine.getCommandLineString() + "\nOutput:\n" + output,
+ 0, result);
+
+ final Set lines = new HashSet(Arrays.asList(StringUtil.convertLineSeparators(output).split("\n")));
+
+ for (Map.Entry entry : testEnv.entrySet()) {
+ final String str = EnvPassingTest.formatEntry(entry);
+ assertTrue("\"" + str + "\" should be in " + lines,
+ lines.contains(str));
+ }
+
+ final Map parentEnv = System.getenv();
+ final List missed = new ArrayList();
+ for (Map.Entry entry : parentEnv.entrySet()) {
+ final String str = EnvPassingTest.formatEntry(entry);
+ if (passParentEnv) {
+ assertTrue("\"" + str + "\" should be in " + lines,
+ lines.contains(str));
+ }
+ else if (lines.contains(str)) {
+ missed.add(str);
+ }
+ }
+ if (!passParentEnv && missed.size() > 0 && parentEnv.size()/missed.size() < 2) {
+ fail(missed + " shouldn't be in " + lines + " (ratio: " + parentEnv.size() + '/' + missed.size() + ')');
+ }
+ }
+}
diff --git a/platform/platform-impl/testSrc/com/intellij/execution/printArgs.c b/platform/platform-impl/testSrc/com/intellij/execution/printArgs.c
new file mode 100644
index 000000000000..54ac7debd176
--- /dev/null
+++ b/platform/platform-impl/testSrc/com/intellij/execution/printArgs.c
@@ -0,0 +1,14 @@
+#include
+
+/**
+ * Invoked from {@link GeneralCommandLineTest} as external process.
+ */
+int main(int argc, char *argv[]) {
+ int i;
+ printf("=====\n");
+ for (i = 1; i < argc; ++i) {
+ printf("%s\n", argv[i]);
+ }
+ printf("=====\n");
+ return 0;
+}
diff --git a/platform/platform-impl/testSrc/com/intellij/execution/printArgs.exe b/platform/platform-impl/testSrc/com/intellij/execution/printArgs.exe
new file mode 100644
index 000000000000..13f43e917733
Binary files /dev/null and b/platform/platform-impl/testSrc/com/intellij/execution/printArgs.exe differ
diff --git a/platform/platform-impl/testSrc/com/intellij/openapi/execution/ParametersListTest.java b/platform/platform-impl/testSrc/com/intellij/openapi/execution/ParametersListTest.java
index 837e6f6fc962..3c7cfd6d55ec 100644
--- a/platform/platform-impl/testSrc/com/intellij/openapi/execution/ParametersListTest.java
+++ b/platform/platform-impl/testSrc/com/intellij/openapi/execution/ParametersListTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2011 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,34 +18,14 @@ package com.intellij.openapi.execution;
import com.intellij.execution.configurations.ParametersList;
import com.intellij.execution.configurations.ParamsGroup;
import com.intellij.testFramework.UsefulTestCase;
-import com.intellij.util.ArrayUtil;
-import com.intellij.util.Assertion;
-import org.jetbrains.annotations.NonNls;
+import java.util.Arrays;
import java.util.Collections;
/**
* @author dyoma
*/
public class ParametersListTest extends UsefulTestCase {
- private final Assertion CHECK = new Assertion();
-
- public void testAddParametersString() {
- checkTokenizer("a b c", new String[]{"a", "b", "c"});
- checkTokenizer("a \"b\"", new String[]{"a", "b"});
- checkTokenizer("a \"b\\\"", new String[]{"a", "b\\\""});
- checkTokenizer("a \"\"", new String[]{"a", "\"\""}); // Bug #12169
- checkTokenizer("a \"x\"", new String[]{"a", "x"});
- checkTokenizer("a \"\" b", new String[]{"a", "\"\"", "b"});
- }
-
- private void checkTokenizer(@NonNls String parmsString, @NonNls String[] expected) {
- ParametersList params = new ParametersList();
- params.addParametersString(parmsString);
- String[] strings = ArrayUtil.toStringArray(params.getList());
- CHECK.compareAll(expected, strings);
- }
-
public void testParamsGroup_Empty() {
ParametersList params = new ParametersList();
@@ -82,7 +62,7 @@ public class ParametersListTest extends UsefulTestCase {
public void testParamsGroup_Remove() {
ParametersList params = new ParametersList();
- final ParamsGroup group1 = params.addParamsGroup("id1");
+ params.addParamsGroup("id1");
final ParamsGroup group2 = params.addParamsGroup("id2");
final ParamsGroup group3 = params.addParamsGroup("id3");
final ParamsGroup group4 = params.addParamsGroup("id4");
@@ -169,20 +149,61 @@ public class ParametersListTest extends UsefulTestCase {
assertEquals("group1_param1 group2_param1 group3_param1", params_clone.getParametersString().trim());
}
- public void testParamsWithSpaces() {
- checkTokenizer("a b=\"some text\" c", new String[]{"a", "b=\"some", "text\"", "c"});
- checkTokenizer("a b=\"some text with spaces\" c", new String[]{"a", "b=\"some", "text", "with", "spaces\"", "c"});
- checkTokenizer("a b=\"some text with spaces\"more c", new String[]{"a", "b=\"some", "text", "with", "spaces\"more", "c"});
- checkTokenizer("a b=\"some text with spaces \"more c", new String[]{"a", "b=\"some", "text", "with", "spaces", "\"more", "c"});
+ public void testAddParametersString() {
+ checkTokenizer("a b c",
+ "a", "b", "c");
+ checkTokenizer("a \"b\"",
+ "a", "b");
+ checkTokenizer("a \"b\\\"",
+ "a", "b\"");
+ checkTokenizer("a \"\"",
+ "a", ""); // Bug #12169
+ checkTokenizer("a \"x\"",
+ "a", "x");
+ checkTokenizer("a \"\\\"\" b",
+ "a", "\"", "b");
+ }
- //this test just fixes the way it works;
- // i don't see any use cases when it definitely should or shouldn't be this way
- checkTokenizer("a \"some text with spaces\"More c", new String[]{"a", "some text with spacesMore", "c"});
+ public void testParamsWithSpacesAndQuotes() {
+ checkTokenizer("a b=\"some text\" c",
+ "a", "b=some text", "c");
+ checkTokenizer("a b=\"some text with spaces\" c",
+ "a", "b=some text with spaces", "c");
+ checkTokenizer("a b=\"some text with spaces\".more c",
+ "a", "b=some text with spaces.more", "c");
+ checkTokenizer("a b=\"some text with spaces \"more c",
+ "a", "b=some text with spaces more", "c");
+ checkTokenizer("a \"some text with spaces\"More c",
+ "a", "some text with spacesMore", "c");
+ checkTokenizer("a \"some text with spaces more c",
+ "a", "some text with spaces more c");
+ checkTokenizer("a\"Some text with spaces \"more c",
+ "aSome text with spaces more", "c");
+ checkTokenizer("a\"Some text with spaces \"more",
+ "aSome text with spaces more");
+ checkTokenizer("a\"Some text with spaces \"more next\"Text moreText\"End c",
+ "aSome text with spaces more", "nextText moreTextEnd", "c");
+ checkTokenizer("\"\"C:\\phing.bat\"",
+ "C:\\phing.bat");
+ checkTokenizer("-Dprop.1=\"some text\" -Dprop.2=\\\"value\\\"",
+ "-Dprop.1=some text", "-Dprop.2=\"value\"");
+ }
- checkTokenizer("a \"some text with spaces \"more c", new String[]{"a", "some text with spaces more", "c"});
- checkTokenizer("a\"some text with spaces \"more c", new String[]{"a\"some", "text", "with", "spaces", "\"more", "c"});
- checkTokenizer("a\"some text with spaces \"more", new String[]{"a\"some", "text", "with", "spaces", "\"more"});
- checkTokenizer("a\"some text with spaces \"more next\"text moreText\"end c", new String[]{"a\"some", "text", "with", "spaces", "\"more",
- "next\"text", "moreText\"end", "c"});
+ public void testJoiningParams() throws Exception {
+ final String[] parameters = {"simpleParam", "param with spaces", "withQuote=\"", "param=\"complex quoted\""};
+ final ParametersList parametersList = new ParametersList();
+
+ parametersList.addAll(parameters);
+ final String joined = parametersList.getParametersString();
+ assertEquals("simpleParam \"param with spaces\" withQuote=\\\" \"param=\\\"complex quoted\\\"\"",
+ joined);
+
+ checkTokenizer(joined, parameters);
+ }
+
+ private static void checkTokenizer(final String paramString, final String... expected) {
+ final ParametersList params = new ParametersList();
+ params.addParametersString(paramString);
+ assertEquals(Arrays.asList(expected), params.getList());
}
}
diff --git a/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidMavenExecutor.java b/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidMavenExecutor.java
index a29c4f78abab..ce7e7b8a5c17 100644
--- a/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidMavenExecutor.java
+++ b/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidMavenExecutor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2010 JetBrains s.r.o.
+ * Copyright 2000-2011 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,7 +22,6 @@ import com.intellij.execution.configurations.JavaParameters;
import com.intellij.openapi.compiler.CompilerMessageCategory;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
-import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.containers.HashMap;
import org.jetbrains.android.util.AndroidUtils;
import org.jetbrains.idea.maven.execution.MavenExternalParameters;
@@ -66,10 +65,6 @@ public class AndroidMavenExecutor {
MavenRunner.getInstance(module.getProject()).getSettings());
GeneralCommandLine commandLine = CommandLineBuilder.createFromJavaParameters(javaParams);
-
- String[] commands = commandLine.getCommands();
- String command = StringUtil.join(commands, " ");
- LOG.info("Execute: " + command);
StringBuilder messageBuilder = new StringBuilder();
boolean success = AndroidUtils.executeCommand(commandLine, messageBuilder);
String message = messageBuilder.toString();
diff --git a/plugins/android/src/org/jetbrains/android/util/AndroidUtils.java b/plugins/android/src/org/jetbrains/android/util/AndroidUtils.java
index 3060fce3a40c..04fb8bed9771 100644
--- a/plugins/android/src/org/jetbrains/android/util/AndroidUtils.java
+++ b/plugins/android/src/org/jetbrains/android/util/AndroidUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2010 JetBrains s.r.o.
+ * Copyright 2000-2011 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -49,7 +49,6 @@ import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.*;
import com.intellij.openapi.util.io.FileUtil;
-import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.ToolWindow;
@@ -468,10 +467,6 @@ public class AndroidUtils {
GeneralCommandLine commandLine,
boolean printOutputToAndroidConsole,
ProcessHandler processHandler) {
- String[] commands = commandLine.getCommands();
- String command = StringUtil.join(commands, " ");
- LOG.info("Execute: " + command);
-
StringBuilder messageBuilder = new StringBuilder();
String result;
boolean success = false;
diff --git a/plugins/git4idea/src/git4idea/commands/GitHandler.java b/plugins/git4idea/src/git4idea/commands/GitHandler.java
index 0f4ca8692e42..af0492298061 100644
--- a/plugins/git4idea/src/git4idea/commands/GitHandler.java
+++ b/plugins/git4idea/src/git4idea/commands/GitHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2011 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -121,7 +121,7 @@ public abstract class GitHandler {
if (myAppSettings != null) {
myCommandLine.setExePath(myAppSettings.getPathToGit());
}
- myCommandLine.setWorkingDirectory(myWorkingDirectory);
+ myCommandLine.setWorkDirectory(myWorkingDirectory);
if (command.name().length() > 0) {
myCommandLine.addParameter(command.name());
}
@@ -428,9 +428,7 @@ public abstract class GitHandler {
* @return a command line with full path to executable replace to "git"
*/
public String printableCommandLine() {
- final GeneralCommandLine line = myCommandLine.clone();
- line.setExePath("git");
- return line.getCommandLineString();
+ return myCommandLine.getCommandLineString("git");
}
/**
diff --git a/plugins/junit/src/com/intellij/execution/junit/TestObject.java b/plugins/junit/src/com/intellij/execution/junit/TestObject.java
index c92f33977957..b0c1d939c99a 100644
--- a/plugins/junit/src/com/intellij/execution/junit/TestObject.java
+++ b/plugins/junit/src/com/intellij/execution/junit/TestObject.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2011 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,14 +32,10 @@ import com.intellij.execution.junit2.ui.model.RootTestInfo;
import com.intellij.execution.junit2.ui.properties.JUnitConsoleProperties;
import com.intellij.execution.process.ProcessAdapter;
import com.intellij.execution.process.ProcessEvent;
-import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.runners.ProgramRunner;
import com.intellij.execution.testframework.*;
import com.intellij.execution.ui.ConsoleViewContentType;
import com.intellij.execution.util.JavaParametersUtil;
-import com.intellij.notification.Notification;
-import com.intellij.notification.NotificationType;
-import com.intellij.notification.Notifications;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
@@ -48,6 +44,7 @@ import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.JavaSdk;
import com.intellij.openapi.projectRoots.JavaSdkType;
+import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.ex.JavaSdkUtil;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.ProjectRootManager;
@@ -68,8 +65,13 @@ import com.intellij.util.IJSwingUtilities;
import com.intellij.util.PathUtil;
import org.jetbrains.annotations.NotNull;
-import java.io.*;
-import java.util.*;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
public abstract class TestObject implements JavaCommandLine {
protected static final Logger LOG = Logger.getInstance("#com.intellij.execution.junit.TestObject");
@@ -147,10 +149,12 @@ public abstract class TestObject implements JavaCommandLine {
return null;
}
+ @Override
public String suggestActionName() {
throw new RuntimeException(String.valueOf(myConfiguration));
}
+ @Override
public boolean isConfiguredByElement(final JUnitConfiguration configuration,
PsiClass testClass,
PsiMethod testMethod,
@@ -158,31 +162,22 @@ public abstract class TestObject implements JavaCommandLine {
return false;
}
+ @Override
public void checkConfiguration() throws RuntimeConfigurationException {
throw new RuntimeConfigurationError(MESSAGE);
}
- public ExecutionResult execute() throws ExecutionException {
- throw createExecutionException();
- }
-
+ @Override
public JavaParameters getJavaParameters() throws ExecutionException {
- throw createExecutionException();
+ throw new ExecutionException(MESSAGE);
}
+ @Override
protected void initialize() throws ExecutionException {
- throw createExecutionException();
- }
-
- protected ProcessHandler startProcess() throws ExecutionException {
- throw createExecutionException();
+ throw new ExecutionException(MESSAGE);
}
};
- private static ExecutionException createExecutionException() {
- return new ExecutionException(MESSAGE);
- }
-
public void checkConfiguration() throws RuntimeConfigurationException{
if (myConfiguration.isAlternativeJrePathEnabled()){
if (myConfiguration.getAlternativeJrePath() == null ||
@@ -216,7 +211,7 @@ public abstract class TestObject implements JavaCommandLine {
}
final Object[] listeners = Extensions.getExtensions(IDEAJUnitListener.EP_NAME);
- final StringBuffer buf = new StringBuffer();
+ final StringBuilder buf = new StringBuilder();
for (final Object listener : listeners) {
boolean enabled = true;
for (RunConfigurationExtension ext : Extensions.getExtensions(RunConfigurationExtension.EP_NAME)) {
@@ -233,7 +228,7 @@ public abstract class TestObject implements JavaCommandLine {
}
if (buf.length() > 0) {
try {
- myListenersFile = FileUtil.createTempFile("junitlisteners", "");
+ myListenersFile = FileUtil.createTempFile("junit_listeners_", "");
myListenersFile.deleteOnExit();
myJavaParameters.getProgramParametersList().add("@@" + myListenersFile.getPath());
FileUtil.writeToFile(myListenersFile, buf.toString().getBytes());
@@ -360,40 +355,42 @@ public abstract class TestObject implements JavaCommandLine {
private void appendForkInfo() throws ExecutionException {
final String forkMode = myConfiguration.getForkMode();
- if (Comparing.strEqual(forkMode, "none")) return;
+ if (Comparing.strEqual(forkMode, "none")) {
+ return;
+ }
+
if (myRunnerSettings.getData() instanceof DebuggingRunnerData) {
- throw new CantRunException("Debug is disabled in fork mode.
Change fork mode to <none> to debug");
- }
- File tempFile = null;
- try {
- tempFile = FileUtil.createTempFile("command.line", "");
- myJavaParameters.getProgramParametersList().add("@@@" + tempFile.getAbsolutePath());
- }
- catch (IOException e) {
- LOG.error(e);
+ throw new CantRunException("Debug is disabled in fork mode.
Please change fork mode to <none> to debug.");
}
+
final JavaParameters javaParameters = getJavaParameters();
+ final Sdk jdk = javaParameters.getJdk();
+ if (jdk == null) {
+ throw new ExecutionException(ExecutionBundle.message("run.configuration.error.no.jdk.specified"));
+ }
+
try {
+ final File tempFile = FileUtil.createTempFile("command.line", "", true);
final PrintWriter writer = new PrintWriter(tempFile, "UTF-8");
try {
- writer.print(GeneralCommandLine
- .quoteParameter(((JavaSdkType)javaParameters.getJdk().getSdkType()).getVMExecutablePath(javaParameters.getJdk())) + " ");
- writer.print(javaParameters.getVMParametersList().getParametersString() + " ");
- writer.print("-classpath ");
- writer.print(GeneralCommandLine.quoteParameter(javaParameters.getClassPath().getPathsString()));
- writer.print("\n" + forkMode);
+ writer.println(((JavaSdkType)jdk.getSdkType()).getVMExecutablePath(jdk));
+ for (String vmParameter : javaParameters.getVMParametersList().getList()) {
+ writer.println(vmParameter);
+ }
+ writer.println("-classpath");
+ writer.println(javaParameters.getClassPath().getPathsString());
}
finally {
writer.close();
}
- tempFile.deleteOnExit();
+
+ myJavaParameters.getProgramParametersList().add("@@@" + forkMode + ',' + tempFile.getAbsolutePath());
}
catch (Exception e) {
LOG.error(e);
}
}
-
protected void addClassesListToJavaParameters(Collection extends T> elements, Function nameFunction, String packageName,
boolean createTempFile,
boolean junit4) {
diff --git a/plugins/junit_rt/src/com/intellij/rt/execution/junit/IdeaTestRunner.java b/plugins/junit_rt/src/com/intellij/rt/execution/junit/IdeaTestRunner.java
index 66a181a95336..49e94d110e0d 100644
--- a/plugins/junit_rt/src/com/intellij/rt/execution/junit/IdeaTestRunner.java
+++ b/plugins/junit_rt/src/com/intellij/rt/execution/junit/IdeaTestRunner.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2011 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,9 +22,7 @@ package com.intellij.rt.execution.junit;
import com.intellij.rt.execution.junit.segments.OutputObjectRegistry;
import com.intellij.rt.execution.junit.segments.SegmentedOutputStream;
-import org.junit.runner.Description;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
diff --git a/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitForkedStarter.java b/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitForkedStarter.java
index 80808d8a0f52..9c4d6890a241 100644
--- a/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitForkedStarter.java
+++ b/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitForkedStarter.java
@@ -19,16 +19,14 @@ import com.intellij.rt.execution.junit.segments.SegmentedOutputStream;
import java.io.*;
import java.util.ArrayList;
-import java.util.Iterator;
import java.util.List;
/**
-* User: anna
-* Date: 4/6/11
-*/
+ * @author anna
+ * @since 6.04.2011
+ */
public class JUnitForkedStarter {
- private JUnitForkedStarter() {
- }
+ private JUnitForkedStarter() { }
public static void main(String[] args) throws Exception {
final String testOutputPath = args[0];
@@ -45,7 +43,9 @@ public class JUnitForkedStarter {
if (!file.createNewFile()) return;
}
final FileOutputStream stream = new FileOutputStream(testOutputPath);
+ //noinspection UseOfSystemOutOrSystemErr
PrintStream oldOut = System.out;
+ //noinspection UseOfSystemOutOrSystemErr
PrintStream oldErr = System.err;
try {
final PrintStream out = new PrintStream(new ForkedVMWrapper(stream, false));
@@ -53,9 +53,11 @@ public class JUnitForkedStarter {
System.setOut(out);
System.setErr(err);
IdeaTestRunner testRunner = (IdeaTestRunner)JUnitStarter.getAgentClass(isJUnit4).newInstance();
+ //noinspection IOResourceOpenedButNotSafelyClosed
testRunner.setStreams(new SegmentedOutputStream(out, true), new SegmentedOutputStream(err, true), lastIdx);
System.exit(testRunner.startRunnerWithArgs(childTestDescription, listeners, false));
- } finally {
+ }
+ finally {
System.setOut(oldOut);
System.setErr(oldErr);
stream.close();
@@ -64,69 +66,85 @@ public class JUnitForkedStarter {
static int startForkedVMs(String[] args,
boolean isJUnit4,
- ArrayList listeners,
+ List listeners,
SegmentedOutputStream out,
- SegmentedOutputStream err, String path) throws Exception {
- final BufferedReader reader = new BufferedReader(new FileReader(path));
- final String commandline = reader.readLine();
- final String forkMode = reader.readLine();
- reader.close();
+ SegmentedOutputStream err,
+ String forkMode,
+ String path) throws Exception {
+ final List parameters = new ArrayList();
+ final BufferedReader bufferedReader = new BufferedReader(new FileReader(path));
+ try {
+ String line;
+ while ((line = bufferedReader.readLine()) != null) {
+ parameters.add(line);
+ }
+ }
+ finally {
+ bufferedReader.close();
+ }
+
IdeaTestRunner testRunner = (IdeaTestRunner)JUnitStarter.getAgentClass(isJUnit4).newInstance();
testRunner.setStreams(out, err, 0);
final Object description = testRunner.getTestToStart(args);
TreeSender.sendTree(testRunner, description);
- long startTime = System.currentTimeMillis();
+ long time = System.currentTimeMillis();
final List children = testRunner.getChildTests(description);
final boolean forkTillMethod = forkMode.equalsIgnoreCase("method");
- int result = processChildren(isJUnit4, listeners, out, err, commandline, testRunner, children, 0, forkTillMethod);
+ int result = processChildren(isJUnit4, listeners, out, err, parameters, testRunner, children, 0, forkTillMethod);
- long endTime = System.currentTimeMillis();
- long runTime = endTime - startTime;
- new TimeSender(testRunner.getRegistry()).printHeader(runTime);
+ time = System.currentTimeMillis() - time;
+ new TimeSender(testRunner.getRegistry()).printHeader(time);
return result;
}
private static int processChildren(boolean isJUnit4,
- ArrayList listeners,
+ List listeners,
SegmentedOutputStream out,
SegmentedOutputStream err,
- String commandline, IdeaTestRunner testRunner, List children, int result, boolean forkTillMethod)
- throws IOException, InterruptedException {
+ List parameters,
+ IdeaTestRunner testRunner,
+ List children,
+ int result,
+ boolean forkTillMethod) throws IOException, InterruptedException {
for (int i = 0, argsLength = children.size(); i < argsLength; i++) {
final Object child = children.get(i);
final List childTests = testRunner.getChildTests(child);
- if (childTests.isEmpty() || !forkTillMethod) {
- result = Math.min(runChild(child, isJUnit4, listeners, out, err, commandline, testRunner, forkTillMethod), result);
- } else {
- result = Math.min(processChildren(isJUnit4, listeners, out, err, commandline, testRunner, childTests, result, forkTillMethod), result);
- }
+ final int childResult = childTests.isEmpty() || !forkTillMethod
+ ? runChild(child, isJUnit4, listeners, out, err, parameters, testRunner, forkTillMethod)
+ : processChildren(isJUnit4, listeners, out, err, parameters, testRunner, childTests, result, forkTillMethod);
+ result = Math.min(childResult, result);
}
return result;
}
private static int runChild(Object child,
boolean isJUnit4,
- ArrayList listeners,
+ List listeners,
SegmentedOutputStream out,
SegmentedOutputStream err,
- String commandline, IdeaTestRunner testRunner,
- boolean forkTillMethod)
- throws IOException, InterruptedException {
+ List parameters,
+ IdeaTestRunner testRunner,
+ boolean forkTillMethod) throws IOException, InterruptedException {
+ //noinspection SSBasedInspection
final File tempFile = File.createTempFile("fork", "test");
final String testOutputPath = tempFile.getAbsolutePath();
final int knownObject = testRunner.getRegistry().getKnownObject(child);
- String command = commandline + " " + JUnitForkedStarter.class.getName()+ " " + testOutputPath + " " + (knownObject + (forkTillMethod ? 0 : 1)) + " " +
- isJUnit4 + " " + testRunner.getStartDescription(child) ;
- for (Iterator iterator = listeners.iterator(); iterator.hasNext(); ) {
- command += " " + iterator.next();
- }
- final Process exec = Runtime.getRuntime().exec(command);
- int result = exec.waitFor();
+
+ final ProcessBuilder builder = new ProcessBuilder();
+ builder.add(parameters);
+ builder.add(JUnitForkedStarter.class.getName());
+ builder.add(testOutputPath);
+ builder.add(String.valueOf(knownObject + (forkTillMethod ? 0 : 1)));
+ builder.add(String.valueOf(isJUnit4));
+ builder.add(testRunner.getStartDescription(child));
+ builder.add(listeners);
+
+ final Process exec = builder.createProcess();
+ final int result = exec.waitFor();
ForkedVMWrapper.readWrapped(testOutputPath, out.getPrintStream(), err.getPrintStream());
- // tempFile.deleteOnExit();
return result;
}
}
diff --git a/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitStarter.java b/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitStarter.java
index c3d281dae47a..f492409c9e18 100644
--- a/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitStarter.java
+++ b/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitStarter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2011 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -34,7 +34,8 @@ public class JUnitStarter {
public static final String IDE_VERSION = "-ideVersion";
public static final String JUNIT4_PARAMETER = "-junit4";
private static final String SOCKET = "-socket";
- private static String ourCommandLine;
+ private static String ourForkMode;
+ private static String ourCommandFileName;
public static void main(String[] args) throws IOException {
SegmentedOutputStream out = new SegmentedOutputStream(System.out);
@@ -77,7 +78,9 @@ public class JUnitStarter {
}
else {
if (arg.startsWith("@@@")) {
- ourCommandLine = arg.substring(3);
+ final int pos = arg.indexOf(',');
+ ourForkMode = arg.substring(3, pos);
+ ourCommandFileName = arg.substring(pos + 1);
continue;
} else if (arg.startsWith("@@")) {
if (new File(arg.substring(2)).exists()) {
@@ -191,8 +194,8 @@ public class JUnitStarter {
try {
System.setOut(new PrintStream(out));
System.setErr(new PrintStream(err));
- if (ourCommandLine != null) {
- return JUnitForkedStarter.startForkedVMs(args, isJUnit4, listeners, out, err, ourCommandLine);
+ if (ourCommandFileName != null) {
+ return JUnitForkedStarter.startForkedVMs(args, isJUnit4, listeners, out, err, ourForkMode, ourCommandFileName);
}
IdeaTestRunner testRunner = (IdeaTestRunner)getAgentClass(isJUnit4).newInstance();
testRunner.setStreams(out, err, 0);
diff --git a/plugins/junit_rt/src/com/intellij/rt/execution/junit/ProcessBuilder.java b/plugins/junit_rt/src/com/intellij/rt/execution/junit/ProcessBuilder.java
new file mode 100644
index 000000000000..5a0e66b97bb7
--- /dev/null
+++ b/plugins/junit_rt/src/com/intellij/rt/execution/junit/ProcessBuilder.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2000-2011 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.rt.execution.junit;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Clone of GeneralCommandLine.
+ */
+public class ProcessBuilder {
+ public static final boolean isWindows = System.getProperty("os.name").toLowerCase().startsWith("windows");
+
+ private final List myParameters = new ArrayList();
+
+ public void add(final String parameter) {
+ myParameters.add(parameter);
+ }
+
+ public void add(final List parameters) {
+ for (int i = 0; i < parameters.size(); i++) {
+ add((String)parameters.get(i));
+ }
+ }
+
+ public Process createProcess() throws IOException {
+ if (myParameters.size() < 1) {
+ throw new IllegalArgumentException("Executable name not specified");
+ }
+
+ final String[] command = new String[myParameters.size()];
+ for (int i = 0; i < myParameters.size(); i++) {
+ command[i] = prepareCommand(myParameters.get(i).toString());
+ }
+
+ return Runtime.getRuntime().exec(command);
+ }
+
+ private static String prepareCommand(String parameter) {
+ // AFAIK, the only thing needed is escaping double quotes on Windows
+ if (isWindows) {
+ final StringBuffer buffer = new StringBuffer(parameter);
+ int pos = 0;
+ while ((pos = parameter.indexOf('\"', pos)) >= 0) {
+ buffer.insert(pos, '\\');
+ pos += 2;
+ }
+ parameter = buffer.toString();
+ }
+ return parameter;
+ }
+}