From 058ffc3f2d508f9979ef014a34bb7c05a35cc8c1 Mon Sep 17 00:00:00 2001 From: Constantine Plotnikov Date: Tue, 29 Jun 2010 22:28:46 +0400 Subject: [PATCH] git4idea: Refactored GitHandler to extract OSProcessHandler to GitTextHandler in order to support binary data handler --- .../src/git4idea/commands/GitHandler.java | 87 ++++-------- .../src/git4idea/commands/GitLineHandler.java | 4 +- .../git4idea/commands/GitSimpleHandler.java | 2 +- .../src/git4idea/commands/GitTextHandler.java | 128 ++++++++++++++++++ 4 files changed, 161 insertions(+), 60 deletions(-) create mode 100644 plugins/git4idea/src/git4idea/commands/GitTextHandler.java diff --git a/plugins/git4idea/src/git4idea/commands/GitHandler.java b/plugins/git4idea/src/git4idea/commands/GitHandler.java index 4f5239b09bc7..1fe5bc89b00b 100644 --- a/plugins/git4idea/src/git4idea/commands/GitHandler.java +++ b/plugins/git4idea/src/git4idea/commands/GitHandler.java @@ -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. diff --git a/plugins/git4idea/src/git4idea/commands/GitLineHandler.java b/plugins/git4idea/src/git4idea/commands/GitLineHandler.java index 5c670e27daf9..6f5c5f46fae3 100644 --- a/plugins/git4idea/src/git4idea/commands/GitLineHandler.java +++ b/plugins/git4idea/src/git4idea/commands/GitLineHandler.java @@ -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 lines, final StringBuilder lineBuilder) { - if (! lines.hasNext()) return; + if (!lines.hasNext()) return; if (lineBuilder.length() > 0) { lineBuilder.append(lines.next()); if (lines.hasNext()) { diff --git a/plugins/git4idea/src/git4idea/commands/GitSimpleHandler.java b/plugins/git4idea/src/git4idea/commands/GitSimpleHandler.java index 160876b7097a..e02183887153 100644 --- a/plugins/git4idea/src/git4idea/commands/GitSimpleHandler.java +++ b/plugins/git4idea/src/git4idea/commands/GitSimpleHandler.java @@ -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 */ diff --git a/plugins/git4idea/src/git4idea/commands/GitTextHandler.java b/plugins/git4idea/src/git4idea/commands/GitTextHandler.java new file mode 100644 index 000000000000..bde48a31e726 --- /dev/null +++ b/plugins/git4idea/src/git4idea/commands/GitTextHandler.java @@ -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(); + } +}