mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-14 18:05:27 +07:00
CPP-34199 Ability to use a PowerShell script as an environment file for toolchains
PS5 and PS7 supported GitOrigin-RevId: 49d169c274539eb749fe30c64681598f0c15e252
This commit is contained in:
committed by
intellij-monorepo-bot
parent
145edae022
commit
08b5d558d0
@@ -2,6 +2,7 @@
|
||||
package com.intellij.util;
|
||||
|
||||
import com.intellij.execution.CommandLineUtil;
|
||||
import com.intellij.execution.configurations.PathEnvironmentVariableUtil;
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
@@ -14,13 +15,22 @@ import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public class EnvReader extends EnvironmentUtil.ShellEnvReader {
|
||||
|
||||
private static final String READ_ENV_CLASS_NAME = ReadEnv.class.getCanonicalName();
|
||||
|
||||
private static @Nullable String readEnvClasspath() {
|
||||
return PathManager.getJarPathForClass(ReadEnv.class);
|
||||
}
|
||||
|
||||
private static @NotNull String javaExePath() {
|
||||
return (System.getProperty("java.home") + "/bin/java").replace('/', File.separatorChar);
|
||||
}
|
||||
|
||||
public EnvReader() {
|
||||
}
|
||||
|
||||
@@ -81,13 +91,12 @@ public class EnvReader extends EnvironmentUtil.ShellEnvReader {
|
||||
callArgs.add("&&");
|
||||
}
|
||||
|
||||
callArgs.add((System.getProperty("java.home") + "/bin/java").replace('/', File.separatorChar)); // NON-NLS
|
||||
callArgs.add(javaExePath()); // NON-NLS
|
||||
callArgs.add("-cp"); // NON-NLS
|
||||
callArgs.add(PathManager.getJarPathForClass(ReadEnv.class));
|
||||
callArgs.add(ReadEnv.class.getCanonicalName());
|
||||
|
||||
callArgs.add(">");
|
||||
callArgs.add(envDataFile.toString());
|
||||
|
||||
callArgs.add("||");
|
||||
callArgs.add("exit"); // NON-NLS
|
||||
callArgs.add("/B"); // NON-NLS
|
||||
@@ -102,6 +111,42 @@ public class EnvReader extends EnvironmentUtil.ShellEnvReader {
|
||||
return new Pair<>(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
@SuppressWarnings("SpellCheckingInspection")
|
||||
public @NotNull Pair<String, Map<String, String>> readPs1OutputAndEnv(
|
||||
@Nullable Path ps1Path,
|
||||
@Nullable List<@NotNull String> args,
|
||||
@NotNull Consumer<? super @NotNull Map<String, String>> scriptEnvironmentProcessor
|
||||
) throws IOException {
|
||||
if (ps1Path != null && !Files.exists(ps1Path)) {
|
||||
throw new NoSuchFileException(ps1Path.toString());
|
||||
}
|
||||
var envDataFile = Files.createTempFile("intellij-cmd-env-data.", ".tmp");
|
||||
final String innerScriptlet;
|
||||
|
||||
if (ps1Path == null) {
|
||||
innerScriptlet = "";
|
||||
}
|
||||
else {
|
||||
var argsStr = args == null ? "" : String.join(" ", args);
|
||||
innerScriptlet = String.format(Locale.ROOT, "& '%s' %s ; if (-not $?) { exit $LASTEXITCODE }; ", ps1Path, argsStr);
|
||||
}
|
||||
|
||||
final var scriptlet = String.format(Locale.ROOT, "& { %s & '%s' -cp '%s' %s '%s' ; exit $LASTEXITCODE }",
|
||||
innerScriptlet, javaExePath(), readEnvClasspath(), READ_ENV_CLASS_NAME, envDataFile.toString());
|
||||
// Powershell 7+ with a falback
|
||||
String shellName = PathEnvironmentVariableUtil.findExecutableInWindowsPath("pwsh", "powershell.exe");
|
||||
var command = List.of(shellName, "-ExecutionPolicy", "Bypass", "-NonInteractive", "-Command", scriptlet);
|
||||
Path workingDir = ps1Path != null ? ps1Path.getParent() : null;
|
||||
var output =
|
||||
runProcessAndReadOutputAndEnvs(command, workingDir, scriptEnvironmentProcessor, envDataFile);
|
||||
return new Pair<>(output.getKey(), output.getValue());
|
||||
|
||||
}
|
||||
|
||||
@NotNull Map<String, String> readPs1Env(Path ps1Path, List<String> args) throws IOException {
|
||||
return readPs1OutputAndEnv(ps1Path, args, (it) -> {}).second;
|
||||
}
|
||||
|
||||
private static @NotNull String prepareCallArgs(@NotNull List<String> callArgs) {
|
||||
List<String> preparedCallArgs = CommandLineUtil.toCommandLine(callArgs);
|
||||
String firstArg = preparedCallArgs.remove(0);
|
||||
|
||||
@@ -2,18 +2,18 @@
|
||||
package com.intellij.util;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus.Internal;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Map;
|
||||
|
||||
@Internal
|
||||
public final class ReadEnv {
|
||||
public static void main(String[] args) throws Exception {
|
||||
try (Writer out = new BufferedWriter(new OutputStreamWriter(System.out,
|
||||
StandardCharsets.UTF_8))) {
|
||||
try (Writer out = new BufferedWriter(createWriter(args))) {
|
||||
for (Map.Entry<String, String> each : System.getenv().entrySet()) {
|
||||
// On Windows, the environment may include variables that start with '=' (https://stackoverflow.com/questions/30102750).
|
||||
// Such variables break the output parser and are unimportant, hence are filtered out.
|
||||
@@ -26,4 +26,14 @@ public final class ReadEnv {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static OutputStreamWriter createWriter(String[] args) throws IOException {
|
||||
if( args.length > 0) {
|
||||
return new OutputStreamWriter(Files.newOutputStream(Paths.get(args[0])), StandardCharsets.UTF_8);
|
||||
} else {
|
||||
return new OutputStreamWriter(System.out,
|
||||
StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,15 @@
|
||||
package com.intellij.util;
|
||||
|
||||
import com.intellij.execution.util.EnvVariablesTable;
|
||||
import com.intellij.openapi.diagnostic.ExceptionWithAttachments;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -66,6 +69,18 @@ public class EnvironmentUtilTest {
|
||||
assertEquals("arg_value", result.get("FOO_TEST_2"));
|
||||
}
|
||||
|
||||
@Test(timeout = 30000)
|
||||
public void loadingPs1Env() throws Exception {
|
||||
assumeWindows();
|
||||
|
||||
File file = FileUtil.createTempFile("test file with spaces", ".ps1", true);
|
||||
FileUtil.writeToFile(file, "$env:FOO_TEST_1=\"123\"\r\n$env:FOO_TEST_2=$($args[0])");
|
||||
|
||||
Map<String, String> result = new EnvReader().readPs1Env(file.toPath(), Collections.singletonList("arg_value"));
|
||||
assertEquals("123", result.get("FOO_TEST_1"));
|
||||
assertEquals("arg_value", result.get("FOO_TEST_2"));
|
||||
}
|
||||
|
||||
@Test(timeout = 30000)
|
||||
public void loadingBatEnv_ErrorHandling() throws Exception {
|
||||
assumeWindows();
|
||||
@@ -78,10 +93,38 @@ public class EnvironmentUtilTest {
|
||||
fail("error should be reported");
|
||||
}
|
||||
catch (Exception e) {
|
||||
assertTrue(e.getMessage(), e.getMessage().contains("some error"));
|
||||
String text = collectTextAndAttachment(e);
|
||||
assertTrue(text, text.contains("some error"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test(timeout = 30000)
|
||||
public void loadingPs1Env_ErrorHandling() throws Exception {
|
||||
assumeWindows();
|
||||
|
||||
File file = FileUtil.createTempFile("test_failure", ".ps1", true);
|
||||
FileUtil.writeToFile(file, "echo \"some failure\"\r\nWrite-Error \"some error\"\r\nexit 100");
|
||||
|
||||
try {
|
||||
new EnvReader().readPs1Env(file.toPath(), Collections.emptyList());
|
||||
fail("error should be reported");
|
||||
}
|
||||
catch (Exception e) {
|
||||
String errorText = collectTextAndAttachment(e);
|
||||
assertTrue(errorText, errorText.contains("some error"));
|
||||
assertTrue(errorText, errorText.contains("some failure"));
|
||||
}
|
||||
}
|
||||
|
||||
private static @NotNull String collectTextAndAttachment(Exception e) {
|
||||
StringBuilder errorTextBuilder = new StringBuilder(e.getMessage());
|
||||
if (e instanceof ExceptionWithAttachments) {
|
||||
Arrays.stream(((ExceptionWithAttachments)e).getAttachments()).forEach(attachment -> errorTextBuilder.append(attachment.getDisplayText()));
|
||||
}
|
||||
String errorText = errorTextBuilder.toString();
|
||||
return errorText;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPath() {
|
||||
String escaped = File.pathSeparator.equals(";") ? "\\;" : File.pathSeparator;
|
||||
|
||||
Reference in New Issue
Block a user