vcs: simplify XmlRpcHandlerService api

Follow-up: 8c64de4cc4dbeddaf648f69b5d96dfe0722c85c7

GitOrigin-RevId: 4ffb641860c7ef4b01ae37a6c0fa0347bba9d99a
This commit is contained in:
Aleksey Pivovarov
2022-02-09 10:59:53 +00:00
committed by intellij-monorepo-bot
parent 20f44eb972
commit e99dec7717
8 changed files with 152 additions and 143 deletions
@@ -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<File> myPaths = new ArrayList<>();
/**
* The internal parameters for the script
*/
private final ArrayList<String> 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<? extends ExternalApp> mainClass, boolean useBatchFile);
}
@@ -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<String> 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<? extends ExternalApp> mainClass, boolean useBatchFile) {
Set<File> 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<File> paths, @NotNull Class<?> clazz) {
paths.add(ScriptGeneratorUtil.getJarFileFor(clazz));
}
}
@@ -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));
}
}
@@ -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;
/**
* <p>The provider of external application scripts called by Git when a remote operation needs communication with the user.</p>
* <p>
* Usage:
* Usage:
* <ol>
* <li>Get the script from {@link #getScriptPath(GitExecutable, boolean)}.</li>
* <li>Set up proper environment variable
@@ -74,13 +73,12 @@ public abstract class XmlRpcHandlerService<T> 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<T> 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<T> implements Disposable {
}
}
}
}
@@ -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);
}
@@ -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<? extends ExternalApp> 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<String> 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;
}
}
@@ -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<String> = 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 {
@@ -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);
}
}