svn: Implemented one common process handler for svn commands (both for terminal and regular mode)

This commit is contained in:
Konstantin Kolosovsky
2014-04-04 13:54:37 +04:00
parent 084e9d4f5f
commit 0ce4ecdd92
7 changed files with 118 additions and 79 deletions
@@ -26,16 +26,16 @@ import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.util.EventDispatcher;
import com.intellij.util.io.BaseDataReader;
import com.intellij.util.io.BinaryOutputReader;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.tmatesoft.svn.core.SVNCancelException;
import java.io.*;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
@@ -57,7 +57,7 @@ public class CommandExecutor {
private volatile boolean myWasCancelled;
protected final GeneralCommandLine myCommandLine;
protected Process myProcess;
protected OSProcessHandler myHandler;
protected SvnProcessHandler myHandler;
private OutputStreamWriter myProcessWriter;
// TODO: Try to implement commands in a way that they manually indicate if they need full output - to prevent situations
// TODO: when large amount of data needs to be stored instead of just sequential processing.
@@ -201,16 +201,18 @@ public class CommandExecutor {
}
@NotNull
protected OSProcessHandler createProcessHandler() {
return needsBinaryOutput()
? new BinaryOSProcessHandler(myProcess, myCommandLine.getCommandLineString())
: new MyOSProcessHandler(myProcess, myCommandLine.getCommandLineString());
protected SvnProcessHandler createProcessHandler() {
return new SvnProcessHandler(myProcess, myCommandLine.getCommandLineString(), needsUtf8Output(), needsBinaryOutput());
}
private boolean needsBinaryOutput() {
protected boolean needsBinaryOutput() {
return SvnCommandName.cat.equals(myCommand.getName());
}
protected boolean needsUtf8Output() {
return myCommand.getParameters().contains("--xml");
}
@NotNull
protected Process createProcess() throws ExecutionException {
return myCommandLine.createProcess();
@@ -237,9 +239,9 @@ public class CommandExecutor {
return outputAdapter.getOutput();
}
@Nullable
@NotNull
public ByteArrayOutputStream getBinaryOutput() {
return myHandler instanceof BinaryOSProcessHandler ? ((BinaryOSProcessHandler)myHandler).myBinaryOutput : null;
return myHandler.getBinaryOutput();
}
// TODO: Carefully here - do not modify command from threads other than the one started command execution
@@ -463,53 +465,4 @@ public class CommandExecutor {
}
}
}
private class MyOSProcessHandler extends OSProcessHandler {
public MyOSProcessHandler(@NotNull Process process, @Nullable String commandLine) {
super(process, commandLine);
}
@Override
protected Reader createProcessOutReader() {
if (myCommand.getParameters().contains("--xml")) {
return new InputStreamReader(myProcess.getInputStream(), CharsetToolkit.UTF8_CHARSET);
}
return super.createProcessOutReader();
}
}
private static class BinaryOSProcessHandler extends OSProcessHandler {
@NotNull private final ByteArrayOutputStream myBinaryOutput;
public BinaryOSProcessHandler(@NotNull final Process process, @Nullable final String commandLine) {
super(process, commandLine);
myBinaryOutput = new ByteArrayOutputStream();
}
@NotNull
@Override
protected BaseDataReader createOutputDataReader(BaseDataReader.SleepingPolicy sleepingPolicy) {
return new SimpleBinaryOutputReader(myProcess.getInputStream(), sleepingPolicy);
}
private class SimpleBinaryOutputReader extends BinaryOutputReader {
public SimpleBinaryOutputReader(@NotNull InputStream stream, SleepingPolicy sleepingPolicy) {
super(stream, sleepingPolicy);
start();
}
@Override
protected void onBinaryAvailable(@NotNull byte[] data, int size) {
myBinaryOutput.write(data, 0, size);
}
@Override
protected Future<?> executeOnPooledThread(Runnable runnable) {
return BinaryOSProcessHandler.this.executeOnPooledThread(runnable);
}
}
}
}
@@ -0,0 +1,91 @@
/*
* Copyright 2000-2014 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 org.jetbrains.idea.svn.commandLine;
import com.intellij.execution.process.OSProcessHandler;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.util.io.BaseDataReader;
import com.intellij.util.io.BinaryOutputReader;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.concurrent.Future;
/**
* @author Konstantin Kolosovsky.
*/
public class SvnProcessHandler extends OSProcessHandler {
private final boolean myForceUtf8;
private final boolean myForceBinary;
@NotNull private final ByteArrayOutputStream myBinaryOutput;
public SvnProcessHandler(@NotNull Process process, boolean forceUtf8, boolean forceBinary) {
this(process, null, forceUtf8, forceBinary);
}
public SvnProcessHandler(@NotNull Process process, @Nullable String commandLine, boolean forceUtf8, boolean forceBinary) {
super(process, commandLine);
myForceUtf8 = forceUtf8;
myForceBinary = forceBinary;
myBinaryOutput = new ByteArrayOutputStream();
}
@NotNull
public ByteArrayOutputStream getBinaryOutput() {
return myBinaryOutput;
}
@Override
protected Reader createProcessOutReader() {
if (myForceUtf8) {
return new InputStreamReader(myProcess.getInputStream(), CharsetToolkit.UTF8_CHARSET);
}
return super.createProcessOutReader();
}
@NotNull
@Override
protected BaseDataReader createOutputDataReader(BaseDataReader.SleepingPolicy sleepingPolicy) {
if (myForceBinary) {
return new SimpleBinaryOutputReader(myProcess.getInputStream(), sleepingPolicy);
}
return super.createOutputDataReader(sleepingPolicy);
}
private class SimpleBinaryOutputReader extends BinaryOutputReader {
public SimpleBinaryOutputReader(@NotNull InputStream stream, SleepingPolicy sleepingPolicy) {
super(stream, sleepingPolicy);
start();
}
@Override
protected void onBinaryAvailable(@NotNull byte[] data, int size) {
myBinaryOutput.write(data, 0, size);
}
@Override
protected Future<?> executeOnPooledThread(Runnable runnable) {
return SvnProcessHandler.this.executeOnPooledThread(runnable);
}
}
}
@@ -17,7 +17,6 @@ package org.jetbrains.idea.svn.commandLine;
import com.intellij.execution.CommandLineUtil;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.process.OSProcessHandler;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.ContainerUtil;
import com.pty4j.PtyProcess;
@@ -53,8 +52,8 @@ public class TerminalExecutor extends CommandExecutor {
@NotNull
@Override
protected OSProcessHandler createProcessHandler() {
return new TerminalProcessHandler(myProcess);
protected SvnProcessHandler createProcessHandler() {
return new TerminalProcessHandler(myProcess, needsUtf8Output(), needsBinaryOutput());
}
@NotNull
@@ -16,7 +16,6 @@
package org.jetbrains.idea.svn.commandLine;
import com.intellij.execution.process.CapturingProcessAdapter;
import com.intellij.execution.process.OSProcessHandler;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.execution.process.ProcessOutputTypes;
import com.intellij.openapi.util.Key;
@@ -31,7 +30,7 @@ import java.util.regex.Matcher;
/**
* @author Konstantin Kolosovsky.
*/
public class TerminalProcessHandler extends OSProcessHandler {
public class TerminalProcessHandler extends SvnProcessHandler {
private final List<InteractiveCommandListener> myInteractiveListeners = ContainerUtil.createLockFreeCopyOnWriteList();
private final CapturingProcessAdapter terminalOutputCapturer = new CapturingProcessAdapter();
@@ -39,8 +38,8 @@ public class TerminalProcessHandler extends OSProcessHandler {
private final StringBuilder outputLine = new StringBuilder();
private final StringBuilder errorLine = new StringBuilder();
public TerminalProcessHandler(@NotNull Process process) {
super(process);
public TerminalProcessHandler(@NotNull Process process, boolean forceUtf8, boolean forceBinary) {
super(process, forceUtf8, forceBinary);
}
public void addInteractiveListener(@NotNull InteractiveCommandListener listener) {
@@ -16,7 +16,6 @@
package org.jetbrains.idea.svn.commandLine;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.process.OSProcessHandler;
import com.intellij.execution.process.ProcessWrapper;
import com.intellij.execution.util.ExecUtil;
import com.intellij.openapi.util.SystemInfo;
@@ -56,8 +55,8 @@ public class WinTerminalExecutor extends TerminalExecutor {
@NotNull
@Override
protected OSProcessHandler createProcessHandler() {
return new WinTerminalProcessHandler(myProcess);
protected SvnProcessHandler createProcessHandler() {
return new WinTerminalProcessHandler(myProcess, needsUtf8Output(), needsBinaryOutput());
}
@Override
@@ -27,8 +27,8 @@ public class WinTerminalProcessHandler extends TerminalProcessHandler {
private static final String NON_CSI_ESCAPE_CODE = "\u001B.[@-_]";
private static final String CSI_ESCAPE_CODE = "\u001B\\[(.*?)[@-~]";
public WinTerminalProcessHandler(@NotNull Process process) {
super(process);
public WinTerminalProcessHandler(@NotNull Process process, boolean forceUtf8, boolean forceBinary) {
super(process, forceUtf8, forceBinary);
}
@Override
@@ -2,15 +2,15 @@ package org.jetbrains.idea.svn.content;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.impl.ContentRevisionCache;
import com.intellij.openapi.vfs.CharsetToolkit;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.api.BaseSvnClient;
import org.jetbrains.idea.svn.commandLine.*;
import org.jetbrains.idea.svn.commandLine.CommandExecutor;
import org.jetbrains.idea.svn.commandLine.CommandUtil;
import org.jetbrains.idea.svn.commandLine.SvnCommandName;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc2.SvnTarget;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.List;
@@ -31,9 +31,7 @@ public class CmdContentClient extends BaseSvnClient implements ContentClient {
CommandUtil.put(parameters, revision);
CommandExecutor command = CommandUtil.execute(myVcs, target, SvnCommandName.cat, parameters, null);
// TODO: currently binary output will be null for terminal mode - use text output in this case
ByteArrayOutputStream output = command.getBinaryOutput();
byte[] bytes = output != null ? output.toByteArray() : CharsetToolkit.getUtf8Bytes(command.getOutput());
byte[] bytes = command.getBinaryOutput().toByteArray();
ContentRevisionCache.checkContentsSize(target.getPathOrUrlString(), bytes.length);