From e99dec77177a7cd043133ee060d6224481e2ef3c Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Tue, 8 Feb 2022 19:36:07 +0300 Subject: [PATCH] vcs: simplify XmlRpcHandlerService api Follow-up: 8c64de4cc4dbeddaf648f69b5d96dfe0722c85c7 GitOrigin-RevId: 4ffb641860c7ef4b01ae37a6c0fa0347bba9d99a --- .../ScriptGenerator.java | 108 +----------------- .../ScriptGeneratorImpl.java | 74 ++++++++++++ .../ScriptGeneratorUtil.java | 9 ++ .../XmlRpcHandlerService.java | 10 +- .../GitHandlerAuthenticationManager.java | 4 +- .../git4idea/commands/GitScriptGenerator.java | 55 +++++++++ .../src/git4idea/config/GitExecutable.kt | 25 +--- .../rebase/GitRebaseEditorService.java | 10 +- 8 files changed, 152 insertions(+), 143 deletions(-) create mode 100644 platform/external-process-auth-helper/src/externalProcessAuthHelper/ScriptGeneratorImpl.java create mode 100644 plugins/git4idea/src/git4idea/commands/GitScriptGenerator.java diff --git a/platform/external-process-auth-helper/src/externalProcessAuthHelper/ScriptGenerator.java b/platform/external-process-auth-helper/src/externalProcessAuthHelper/ScriptGenerator.java index 5b7981c0076a..ad06c7ddf72d 100644 --- a/platform/external-process-auth-helper/src/externalProcessAuthHelper/ScriptGenerator.java +++ b/platform/external-process-auth-helper/src/externalProcessAuthHelper/ScriptGenerator.java @@ -1,112 +1,10 @@ // Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.externalProcessAuthHelper; -import com.intellij.openapi.util.SystemInfo; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.util.PathUtil; -import com.intellij.util.containers.ContainerUtil; import externalApp.ExternalApp; -import org.apache.commons.codec.DecoderException; -import org.apache.xmlrpc.XmlRpcClientLite; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import java.io.File; -import java.util.ArrayList; - -/** - * Script generator utility class. It uses to generate a temporary scripts that - * are removed after application ends. - */ -public class ScriptGenerator { - /** - * The scripts may class - */ - private final Class myMainClass; - /** - * The class paths for the script - */ - private final ArrayList myPaths = new ArrayList<>(); - /** - * The internal parameters for the script - */ - private final ArrayList myInternalParameters = new ArrayList<>(); - - /** - * @param mainClass the script main class - */ - public ScriptGenerator(@NotNull Class mainClass) { - myMainClass = mainClass; - addClasses(myMainClass); - addClasses(ExternalApp.class); - addClasses(XmlRpcClientLite.class, DecoderException.class); - } - - /** - * Add jar or directory that contains the class to the classpath - * - * @param classes classes which sources will be added - */ - private void addClasses(final Class... classes) { - for (Class c : classes) { - File classPath = new File(PathUtil.getJarPathForClass(c)); - if (!myPaths.contains(classPath)) { - // the size of path is expected to be quite small, so no optimization is done here - myPaths.add(classPath); - } - } - } - - /** - * Add internal parameters for the script - * - * @param parameters internal parameters - * @return this script generator - */ - public ScriptGenerator addInternal(@NonNls String... parameters) { - ContainerUtil.addAll(myInternalParameters, parameters); - return this; - } - - /** - * @return a command line for the customCmdBuilder program - */ - @NonNls - public String commandLine(@Nullable CustomScriptCommandLineBuilder customCmdBuilder) { - @NonNls StringBuilder cmd = new StringBuilder(); - - if (customCmdBuilder != null) { - customCmdBuilder.buildJavaCmd(cmd); - } - else { - cmd.append('"'); - cmd.append(String.format("%s/bin/java", System.getProperty("java.home"))); - cmd.append('"'); - } - - cmd.append(" -cp "); - cmd.append('"'); - String classpathSeparator = String.valueOf(File.pathSeparatorChar); - cmd.append(StringUtil.join(myPaths, file -> file.getPath(), classpathSeparator)); - cmd.append('"'); - - cmd.append(' '); - cmd.append(myMainClass.getName()); - - for (String p : myInternalParameters) { - cmd.append(' '); - cmd.append(p); - } - - String line = cmd.toString(); - if (SystemInfo.isWindows) { - line = line.replace('\\', '/'); - } - return line; - } - - public interface CustomScriptCommandLineBuilder { - void buildJavaCmd(StringBuilder cmd); - } +public interface ScriptGenerator { + @NotNull + String commandLine(@NotNull Class mainClass, boolean useBatchFile); } diff --git a/platform/external-process-auth-helper/src/externalProcessAuthHelper/ScriptGeneratorImpl.java b/platform/external-process-auth-helper/src/externalProcessAuthHelper/ScriptGeneratorImpl.java new file mode 100644 index 000000000000..3bc8e2118c01 --- /dev/null +++ b/platform/external-process-auth-helper/src/externalProcessAuthHelper/ScriptGeneratorImpl.java @@ -0,0 +1,74 @@ +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.externalProcessAuthHelper; + +import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.containers.ContainerUtil; +import externalApp.ExternalApp; +import org.apache.commons.codec.DecoderException; +import org.apache.xmlrpc.XmlRpcClientLite; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +public class ScriptGeneratorImpl implements ScriptGenerator { + private final List myInternalParameters = new ArrayList<>(); + + /** + * Add internal parameters for the script + */ + @NotNull + public ScriptGeneratorImpl addParameters(@NonNls String... parameters) { + ContainerUtil.addAll(myInternalParameters, parameters); + return this; + } + + @Override + public @NotNull String commandLine(@NotNull Class mainClass, boolean useBatchFile) { + Set jarPaths = new LinkedHashSet<>(); + addClasses(jarPaths, mainClass); + addClasses(jarPaths, ExternalApp.class); + addClasses(jarPaths, XmlRpcClientLite.class); + addClasses(jarPaths, DecoderException.class); + + @NonNls StringBuilder cmd = new StringBuilder(); + + cmd.append('"'); + cmd.append(getJavaExecutablePath()); + cmd.append('"'); + + cmd.append(" -cp "); + cmd.append('"'); + String classpathSeparator = String.valueOf(File.pathSeparatorChar); + cmd.append(StringUtil.join(jarPaths, file -> file.getPath(), classpathSeparator)); + cmd.append('"'); + + cmd.append(' '); + cmd.append(mainClass.getName()); + + for (String p : myInternalParameters) { + cmd.append(' '); + cmd.append(p); + } + + String line = cmd.toString(); + if (SystemInfo.isWindows) { + line = line.replace('\\', '/'); + } + return line; + } + + @NotNull + protected String getJavaExecutablePath() { + return String.format("%s/bin/java", System.getProperty("java.home")); + } + + private static void addClasses(@NotNull Set paths, @NotNull Class clazz) { + paths.add(ScriptGeneratorUtil.getJarFileFor(clazz)); + } +} diff --git a/platform/external-process-auth-helper/src/externalProcessAuthHelper/ScriptGeneratorUtil.java b/platform/external-process-auth-helper/src/externalProcessAuthHelper/ScriptGeneratorUtil.java index 8074c1908539..77387c1c74f0 100644 --- a/platform/external-process-auth-helper/src/externalProcessAuthHelper/ScriptGeneratorUtil.java +++ b/platform/external-process-auth-helper/src/externalProcessAuthHelper/ScriptGeneratorUtil.java @@ -3,6 +3,7 @@ package com.intellij.externalProcessAuthHelper; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.util.PathUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -40,4 +41,12 @@ public class ScriptGeneratorUtil { return useBatchFile ? createBatchScript(fileNamePrefix, commandLine) : createShellScript(fileNamePrefix, commandLine); } + + /** + * @return jar or directory that contains the class for the classpath + */ + @NotNull + public static File getJarFileFor(@NotNull Class clazz) { + return new File(PathUtil.getJarPathForClass(clazz)); + } } diff --git a/platform/external-process-auth-helper/src/externalProcessAuthHelper/XmlRpcHandlerService.java b/platform/external-process-auth-helper/src/externalProcessAuthHelper/XmlRpcHandlerService.java index 320a2693a7e6..086795411e16 100644 --- a/platform/external-process-auth-helper/src/externalProcessAuthHelper/XmlRpcHandlerService.java +++ b/platform/external-process-auth-helper/src/externalProcessAuthHelper/XmlRpcHandlerService.java @@ -8,7 +8,6 @@ import com.intellij.openapi.diagnostic.Logger; import externalApp.ExternalApp; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.jetbrains.ide.BuiltInServerManager; import java.io.File; @@ -20,7 +19,7 @@ import java.util.UUID; /** *

The provider of external application scripts called by Git when a remote operation needs communication with the user.

*

- * Usage: + * Usage: *

    *
  1. Get the script from {@link #getScriptPath(GitExecutable, boolean)}.
  2. *
  3. Set up proper environment variable @@ -74,13 +73,12 @@ public abstract class XmlRpcHandlerService implements Disposable { * @throws IOException if script cannot be generated */ @NotNull - public File getScriptPath(@NotNull String scriptId, boolean useBatchFile, @Nullable ScriptGenerator.CustomScriptCommandLineBuilder customCmdBuilder) throws IOException { + public File getScriptPath(@NotNull String scriptId, @NotNull ScriptGenerator generator, boolean useBatchFile) throws IOException { synchronized (SCRIPT_FILE_LOCK) { String id = scriptId + (useBatchFile ? "-bat" : ""); //NON-NLS File scriptPath = myScriptPaths.get(id); if (scriptPath == null || !scriptPath.exists()) { - ScriptGenerator generator = new ScriptGenerator(myScriptMainClass); - String commandLine = generator.commandLine(customCmdBuilder); + String commandLine = generator.commandLine(myScriptMainClass, useBatchFile); scriptPath = ScriptGeneratorUtil.createTempScript(commandLine, myScriptTempFilePrefix + "-" + scriptId, useBatchFile); myScriptPaths.put(id, scriptPath); } @@ -119,6 +117,7 @@ public abstract class XmlRpcHandlerService implements Disposable { /** * Creates an implementation of the xml rpc handler, which methods will be called from the external application. * This method should just delegate the call to the specific handler of type {@link T}, which can be achieved by {@link #getHandler(UUID)}. + * * @return New instance of the xml rpc handler delegate. */ @NotNull @@ -153,5 +152,4 @@ public abstract class XmlRpcHandlerService implements Disposable { } } } - } diff --git a/plugins/git4idea/src/git4idea/commands/GitHandlerAuthenticationManager.java b/plugins/git4idea/src/git4idea/commands/GitHandlerAuthenticationManager.java index 6654b7a1c816..5e249e7a9900 100644 --- a/plugins/git4idea/src/git4idea/commands/GitHandlerAuthenticationManager.java +++ b/plugins/git4idea/src/git4idea/commands/GitHandlerAuthenticationManager.java @@ -139,7 +139,6 @@ public final class GitHandlerAuthenticationManager implements AutoCloseable { if (useSchannel) { myHandler.overwriteConfig("http.sslBackend=schannel"); } - } private void cleanupHttpAuth() { @@ -184,8 +183,7 @@ public final class GitHandlerAuthenticationManager implements AutoCloseable { executable.isLocal() && (!Registry.is("git.use.shell.script.on.windows") || !GitVersionSpecialty.CAN_USE_SHELL_HELPER_SCRIPT_ON_WINDOWS.existsIn(myVersion)); - File scriptFile = service.getScriptPath(executable.getId(), useBatchFile, executable instanceof ScriptGenerator.CustomScriptCommandLineBuilder - ? (ScriptGenerator.CustomScriptCommandLineBuilder)executable : null); + File scriptFile = service.getScriptPath(executable.getId(), new GitScriptGenerator(executable), useBatchFile); myHandler.addCustomEnvironmentVariable(env, scriptFile); } diff --git a/plugins/git4idea/src/git4idea/commands/GitScriptGenerator.java b/plugins/git4idea/src/git4idea/commands/GitScriptGenerator.java new file mode 100644 index 000000000000..24ebfd32b685 --- /dev/null +++ b/plugins/git4idea/src/git4idea/commands/GitScriptGenerator.java @@ -0,0 +1,55 @@ +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package git4idea.commands; + +import com.intellij.externalProcessAuthHelper.ScriptGeneratorImpl; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.containers.ContainerUtil; +import externalApp.ExternalApp; +import externalApp.nativessh.NativeSshAskPassXmlRpcHandler; +import git4idea.config.GitExecutable; +import git4idea.editor.GitRebaseEditorXmlRpcHandler; +import git4idea.http.GitAskPassXmlRpcHandler; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.util.List; + +public class GitScriptGenerator extends ScriptGeneratorImpl { + private final GitExecutable myExecutable; + + public GitScriptGenerator(@NotNull GitExecutable executable) { + myExecutable = executable; + } + + @Override + protected @NotNull String getJavaExecutablePath() { + if (myExecutable instanceof GitExecutable.Wsl) { + File javaExecutable = new File(String.format("%s\\bin\\java.exe", System.getProperty("java.home"))); + return myExecutable.convertFilePath(javaExecutable); + } + return super.getJavaExecutablePath(); + } + + @Override + public @NotNull String commandLine(@NotNull Class mainClass, boolean useBatchFile) { + String commandLine = super.commandLine(mainClass, useBatchFile); + + if (myExecutable instanceof GitExecutable.Wsl) { + // pass ENV variables from git to java command + StringBuilder sb = new StringBuilder(); + List envs = ContainerUtil.newArrayList( + NativeSshAskPassXmlRpcHandler.IJ_SSH_ASK_PASS_HANDLER_ENV, + NativeSshAskPassXmlRpcHandler.IJ_SSH_ASK_PASS_PORT_ENV, + GitAskPassXmlRpcHandler.IJ_ASK_PASS_HANDLER_ENV, + GitAskPassXmlRpcHandler.IJ_ASK_PASS_PORT_ENV, + GitRebaseEditorXmlRpcHandler.IJ_EDITOR_HANDLER_ENV); + sb.append("export WSLENV="); + sb.append(StringUtil.join(envs, it -> it + "/w", ":")); + sb.append("\n"); + + sb.append(commandLine); + return sb.toString(); + } + return commandLine; + } +} diff --git a/plugins/git4idea/src/git4idea/config/GitExecutable.kt b/plugins/git4idea/src/git4idea/config/GitExecutable.kt index 871a695e6b0f..dd0d0fc2fc17 100644 --- a/plugins/git4idea/src/git4idea/config/GitExecutable.kt +++ b/plugins/git4idea/src/git4idea/config/GitExecutable.kt @@ -7,17 +7,12 @@ import com.intellij.execution.configurations.GeneralCommandLine import com.intellij.execution.util.ExecUtil import com.intellij.execution.wsl.WSLCommandLineOptions import com.intellij.execution.wsl.WSLDistribution -import com.intellij.externalProcessAuthHelper.ScriptGenerator import com.intellij.openapi.project.Project import com.intellij.openapi.util.SystemInfo import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.util.registry.Registry import com.intellij.openapi.util.text.StringUtil -import com.intellij.util.containers.ContainerUtil -import externalApp.nativessh.NativeSshAskPassXmlRpcHandler import git4idea.commands.GitHandler -import git4idea.editor.GitRebaseEditorXmlRpcHandler -import git4idea.http.GitAskPassXmlRpcHandler import git4idea.i18n.GitBundle import org.jetbrains.annotations.Nls import org.jetbrains.annotations.NonNls @@ -93,27 +88,9 @@ sealed class GitExecutable { data class Wsl(override val exePath: String, val distribution: WSLDistribution) - : GitExecutable(), ScriptGenerator.CustomScriptCommandLineBuilder { + : GitExecutable() { override val id: String = "wsl-${distribution.id}" override val isLocal: Boolean = false - override fun buildJavaCmd(cmd: StringBuilder) { - val envs: List = ContainerUtil.newArrayList( - NativeSshAskPassXmlRpcHandler.IJ_SSH_ASK_PASS_HANDLER_ENV, - NativeSshAskPassXmlRpcHandler.IJ_SSH_ASK_PASS_PORT_ENV, - GitAskPassXmlRpcHandler.IJ_ASK_PASS_HANDLER_ENV, - GitAskPassXmlRpcHandler.IJ_ASK_PASS_PORT_ENV, - GitRebaseEditorXmlRpcHandler.IJ_EDITOR_HANDLER_ENV) - cmd.append("export WSLENV=") - cmd.append(StringUtil.join(envs, - { it: String -> "$it/w" }, ":")) - cmd.append("\n") - - cmd.append('"') - val javaExecutable = File(String.format("%s\\bin\\java.exe", System.getProperty("java.home"))) - cmd.append(convertFilePath(javaExecutable)) - cmd.append('"') - } - override fun toString(): String = "${distribution.presentableName}: $exePath" override fun convertFilePath(file: File): String { diff --git a/plugins/git4idea/src/git4idea/rebase/GitRebaseEditorService.java b/plugins/git4idea/src/git4idea/rebase/GitRebaseEditorService.java index 714fb240d33f..b21ddf558b6d 100644 --- a/plugins/git4idea/src/git4idea/rebase/GitRebaseEditorService.java +++ b/plugins/git4idea/src/git4idea/rebase/GitRebaseEditorService.java @@ -1,13 +1,13 @@ // Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package git4idea.rebase; -import com.intellij.externalProcessAuthHelper.ScriptGenerator; import com.intellij.ide.XmlRpcServer; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.Service; import com.intellij.openapi.util.Pair; import git4idea.commands.GitHandler; +import git4idea.commands.GitScriptGenerator; import git4idea.config.GitExecutable; import git4idea.editor.GitRebaseEditorApp; import git4idea.editor.GitRebaseEditorXmlRpcHandler; @@ -72,10 +72,10 @@ public final class GitRebaseEditorService implements Disposable { @NotNull public synchronized String getEditorCommand(@NotNull GitExecutable executable) { synchronized (myScriptLock) { - ScriptGenerator generator = new ScriptGenerator(GitRebaseEditorApp.class); - generator.addInternal(Integer.toString(BuiltInServerManager.getInstance().waitForStart().getPort())); - return generator.commandLine(executable instanceof ScriptGenerator.CustomScriptCommandLineBuilder - ? (ScriptGenerator.CustomScriptCommandLineBuilder)executable : null); + int port = BuiltInServerManager.getInstance().waitForStart().getPort(); + return new GitScriptGenerator(executable) + .addParameters(Integer.toString(port)) + .commandLine(GitRebaseEditorApp.class, false); } }