git4idea: Refactored GitHandler to extract OSProcessHandler to GitTextHandler in order to support binary data handler

This commit is contained in:
Constantine Plotnikov
2010-06-30 00:05:23 +04:00
parent 25569c08d6
commit 058ffc3f2d
4 changed files with 161 additions and 60 deletions
@@ -16,12 +16,8 @@
package git4idea.commands;
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.execution.process.OSProcessHandler;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.execution.process.ProcessListener;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vfs.LocalFileSystem;
@@ -61,16 +57,11 @@ public abstract class GitHandler {
/**
* a command line
*/
private final GeneralCommandLine myCommandLine;
/**
* wrapped process handler
*/
// note that access is safe because it accessed in unsynchronized block only after process is started, and it does not change after that
@SuppressWarnings({"FieldAccessedSynchronizedAndUnsynchronized"}) private OSProcessHandler myHandler;
final GeneralCommandLine myCommandLine;
/**
* process
*/
private Process myProcess;
@SuppressWarnings({"FieldAccessedSynchronizedAndUnsynchronized"}) Process myProcess;
/**
* If true, the standard output is not copied to version control console
*/
@@ -193,6 +184,13 @@ public abstract class GitHandler {
this(project, VfsUtil.virtualToIoFile(vcsRoot), command);
}
/**
* @return multicaster for listeners
*/
protected GitHandlerListener listeners() {
return myListeners.getMulticaster();
}
/**
* Add error code to ignored list
*
@@ -433,34 +431,7 @@ public abstract class GitHandler {
myCommandLine.setEnvParams(myEnv);
// start process
myProcess = myCommandLine.createProcess();
myHandler = new OSProcessHandler(myProcess, myCommandLine.getCommandLineString()) {
@Override
public Charset getCharset() {
return myCharset == null ? super.getCharset() : myCharset;
}
};
myHandler.addProcessListener(new ProcessListener() {
public void startNotified(final ProcessEvent event) {
// do nothing
}
public void processTerminated(final ProcessEvent event) {
final int exitCode = event.getExitCode();
setExitCode(exitCode);
cleanupEnv();
GitHandler.this.processTerminated(exitCode);
myListeners.getMulticaster().processTerminated(exitCode);
}
public void processWillTerminate(final ProcessEvent event, final boolean willBeDestroyed) {
// do nothing
}
public void onTextAvailable(final ProcessEvent event, final Key outputType) {
GitHandler.this.onTextAvailable(event.getText(), outputType);
}
});
myHandler.startNotify();
startHandlingStreams();
}
catch (Throwable t) {
cleanupEnv();
@@ -468,6 +439,11 @@ public abstract class GitHandler {
}
}
/**
* Start handling streams for the handler
*/
protected abstract void startHandlingStreams();
/**
* Notification for handler to handle process exit event
*
@@ -484,14 +460,6 @@ public abstract class GitHandler {
return line.getCommandLineString();
}
/**
* This method is invoked when some text is available
*
* @param text an available text
* @param outputType output type
*/
protected abstract void onTextAvailable(final String text, final Key outputType);
/**
* Cancel activity
*/
@@ -500,14 +468,14 @@ public abstract class GitHandler {
if (!myIsCancellable) {
throw new IllegalStateException("The process is not cancellable.");
}
try {
myHandler.destroyProcess();
}
catch (Exception e) {
log.warn("Exception during cancel", e);
}
destroyProcess();
}
/**
* Destroy process
*/
protected abstract void destroyProcess();
/**
* @return exit code for process if it is available
*/
@@ -521,14 +489,14 @@ public abstract class GitHandler {
/**
* @param exitCode a exit code for process
*/
private synchronized void setExitCode(int exitCode) {
protected synchronized void setExitCode(int exitCode) {
myExitCode = exitCode;
}
/**
* Cleanup environment
*/
private synchronized void cleanupEnv() {
protected synchronized void cleanupEnv() {
if (!myNoSSHFlag && !myEnvironmentCleanedUp) {
GitSSHService ssh = GitSSHIdeaService.getInstance();
myEnvironmentCleanedUp = true;
@@ -543,14 +511,19 @@ public abstract class GitHandler {
checkStarted();
try {
if (myInputProcessor != null) {
myInputProcessor.process(myHandler.getProcessInput());
myInputProcessor.process(myProcess.getOutputStream());
}
}
finally {
myHandler.waitFor();
waitForProcess();
}
}
/**
* Wait for process
*/
protected abstract void waitForProcess();
/**
* Set silent mode. When handler is silent, it does not logs command in version control console.
* Note that this option also suppresses stderr and stdout copying.
@@ -30,7 +30,7 @@ import java.util.List;
/**
* The handler that is based on per-line processing of the text.
*/
public class GitLineHandler extends GitHandler {
public class GitLineHandler extends GitTextHandler {
/**
* the partial line from stdout stream
*/
@@ -112,7 +112,7 @@ public class GitLineHandler extends GitHandler {
* @param lineBuilder a line builder
*/
private void notifyLines(final Key outputType, final Iterator<String> lines, final StringBuilder lineBuilder) {
if (! lines.hasNext()) return;
if (!lines.hasNext()) return;
if (lineBuilder.length() > 0) {
lineBuilder.append(lines.next());
if (lines.hasNext()) {
@@ -33,7 +33,7 @@ import java.util.concurrent.Semaphore;
* The class also includes a number of static utility methods that represent some
* simple commands.
*/
public class GitSimpleHandler extends GitHandler {
public class GitSimpleHandler extends GitTextHandler {
/**
* Stderr output
*/
@@ -0,0 +1,128 @@
/*
* Copyright 2000-2010 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 git4idea.commands;
import com.intellij.execution.process.OSProcessHandler;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.execution.process.ProcessListener;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.nio.charset.Charset;
/**
* The handler for git commands with text outputs
*/
public abstract class GitTextHandler extends GitHandler {
/**
* the logger
*/
private static final Logger log = Logger.getInstance(GitTextHandler.class.getName());
/**
* wrapped process handler
*/
// note that access is safe because it accessed in unsynchronized block only after process is started, and it does not change after that
@SuppressWarnings({"FieldAccessedSynchronizedAndUnsynchronized"}) private OSProcessHandler myHandler;
/**
* The constructor from super
*
* @param project the project
* @param directory the command directory
* @param command the command
*/
protected GitTextHandler(@NotNull Project project, @NotNull File directory, @NotNull GitCommand command) {
super(project, directory, command);
}
/**
* The constructor
*
* @param project the project
* @param vcsRoot the vcs root
* @param command the command to run
*/
protected GitTextHandler(final Project project, final VirtualFile vcsRoot, final GitCommand command) {
super(project, vcsRoot, command);
}
/**
* {@inheritDoc}
*/
protected void startHandlingStreams() {
myHandler = new OSProcessHandler(myProcess, myCommandLine.getCommandLineString()) {
@Override
public Charset getCharset() {
Charset charset = GitTextHandler.this.getCharset();
return charset == null ? super.getCharset() : charset;
}
};
myHandler.addProcessListener(new ProcessListener() {
public void startNotified(final ProcessEvent event) {
// do nothing
}
public void processTerminated(final ProcessEvent event) {
final int exitCode = event.getExitCode();
setExitCode(exitCode);
cleanupEnv();
GitTextHandler.this.processTerminated(exitCode);
listeners().processTerminated(exitCode);
}
public void processWillTerminate(final ProcessEvent event, final boolean willBeDestroyed) {
// do nothing
}
public void onTextAvailable(final ProcessEvent event, final Key outputType) {
GitTextHandler.this.onTextAvailable(event.getText(), outputType);
}
});
myHandler.startNotify();
}
/**
* This method is invoked when some text is available
*
* @param text an available text
* @param outputType output type
*/
protected abstract void onTextAvailable(final String text, final Key outputType);
/**
* {@inheritDoc}
*/
protected void destroyProcess() {
try {
myHandler.destroyProcess();
}
catch (Exception e) {
log.warn("Exception during cancel", e);
}
}
/**
* {@inheritDoc}
*/
protected void waitForProcess() {
myHandler.waitFor();
}
}