/java/java-runtime/src/com/intellij/rt/execution/testFrameworks/ProcessBuilder.java

https://github.com/JetBrains/intellij-community · Java · 126 lines · 78 code · 19 blank · 29 comment · 16 complexity · e799f6eef36f8a2dd49e2df799e929c2 MD5 · raw file

  1. /*
  2. * Copyright 2000-2017 JetBrains s.r.o.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package com.intellij.rt.execution.testFrameworks;
  17. import java.io.File;
  18. import java.io.IOException;
  19. import java.util.ArrayList;
  20. import java.util.List;
  21. import java.util.Locale;
  22. /**
  23. * Clone of GeneralCommandLine.
  24. */
  25. public class ProcessBuilder {
  26. public static final boolean isWindows = isWindows();
  27. private static boolean isWindows() {
  28. try {
  29. return System.getProperty("os.name").toLowerCase(Locale.ENGLISH).startsWith("windows");
  30. }
  31. catch (SecurityException e) {
  32. return false;
  33. }
  34. }
  35. private static final String WIN_SHELL_SPECIALS = "&<>()@^|";
  36. private final List<String> myParameters = new ArrayList<String>();
  37. private File myWorkingDir = null;
  38. public void add(final String parameter) {
  39. myParameters.add(parameter);
  40. }
  41. public void add(final List<String> parameters) {
  42. for (String parameter : parameters) {
  43. add(parameter);
  44. }
  45. }
  46. public void setWorkingDir(File workingDir) {
  47. myWorkingDir = workingDir;
  48. }
  49. // please keep an implementation in sync with [util] CommandLineUtil.toCommandLine()
  50. //
  51. // Comparing to the latter, this is a simplified version with the following limitations on Windows (neither of these
  52. // seems to be used in our cases though):
  53. //
  54. // - does not fully handle \" escaping (must escape quoted ["C:\Program Files\"] -> [\"C:\Program Files\\\"])
  55. // - does not support `cmd.exe /c call command args-with-special-chars-[&<>()@^|]
  56. // - does not handle special chars [&<>()@^|] interleaved with quotes ["] properly (the quote flag)
  57. // - mangles the output of `cmd.exe /c echo ...`
  58. //
  59. // If either of these becomes an issue, please refer to [util] CommandLineUtil.addToWindowsCommandLine() for a possible implementation.
  60. public Process createProcess() throws IOException {
  61. if (myParameters.size() < 1) {
  62. throw new IllegalArgumentException("Executable name not specified");
  63. }
  64. String command = myParameters.get(0);
  65. boolean winShell = isWindows && isWinShell(command);
  66. String[] commandLine = new String[myParameters.size()];
  67. commandLine[0] = command;
  68. for (int i = 1; i < myParameters.size(); i++) {
  69. String parameter = myParameters.get(i);
  70. if (isWindows) {
  71. int pos = parameter.indexOf('\"');
  72. if (pos >= 0) {
  73. StringBuilder buffer = new StringBuilder(parameter);
  74. do {
  75. buffer.insert(pos, '\\');
  76. pos += 2;
  77. }
  78. while ((pos = parameter.indexOf('\"', pos)) >= 0);
  79. parameter = buffer.toString();
  80. }
  81. else if (parameter.length() == 0) {
  82. parameter = "\"\"";
  83. }
  84. if (winShell && containsAnyChar(parameter, WIN_SHELL_SPECIALS)) {
  85. parameter = '"' + parameter + '"';
  86. }
  87. }
  88. commandLine[i] = parameter;
  89. }
  90. return Runtime.getRuntime().exec(commandLine, null, myWorkingDir);
  91. }
  92. private static boolean isWinShell(String command) {
  93. return endsWithIgnoreCase(command, ".cmd") || endsWithIgnoreCase(command, ".bat") ||
  94. "cmd".equalsIgnoreCase(command) || "cmd.exe".equalsIgnoreCase(command);
  95. }
  96. private static boolean endsWithIgnoreCase(String str, String suffix) {
  97. return str.regionMatches(true, str.length() - suffix.length(), suffix, 0, suffix.length());
  98. }
  99. private static boolean containsAnyChar(String value, String chars) {
  100. for (int i = 0; i < value.length(); i++) {
  101. if (chars.indexOf(value.charAt(i)) >= 0) {
  102. return true;
  103. }
  104. }
  105. return false;
  106. }
  107. }