diff --git a/plugins/git4idea/src/git4idea/GitContentRevision.java b/plugins/git4idea/src/git4idea/GitContentRevision.java index 223b583e3830..4338622da081 100644 --- a/plugins/git4idea/src/git4idea/GitContentRevision.java +++ b/plugins/git4idea/src/git4idea/GitContentRevision.java @@ -24,8 +24,8 @@ import com.intellij.openapi.vcs.changes.CurrentContentRevision; import com.intellij.openapi.vcs.history.VcsRevisionNumber; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.vcsUtil.VcsUtil; +import git4idea.commands.GitBinaryHandler; import git4idea.commands.GitCommand; -import git4idea.commands.GitSimpleHandler; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -69,12 +69,13 @@ public class GitContentRevision implements ContentRevision { return null; } VirtualFile root = GitUtil.getGitRoot(myFile); - GitSimpleHandler h = new GitSimpleHandler(myProject, root, GitCommand.SHOW); + GitBinaryHandler h = new GitBinaryHandler(myProject, root, GitCommand.SHOW); h.setCharset(myCharset); h.setNoSSH(true); h.setSilent(true); h.addParameters(myRevision.getRev() + ":" + GitUtil.relativePath(root, myFile)); - return h.run(); + byte[] result = h.run(); + return new String(result, h.getCharset()); } @NotNull diff --git a/plugins/git4idea/src/git4idea/GitFileRevision.java b/plugins/git4idea/src/git4idea/GitFileRevision.java index 81911bce43f9..137bed77cec9 100644 --- a/plugins/git4idea/src/git4idea/GitFileRevision.java +++ b/plugins/git4idea/src/git4idea/GitFileRevision.java @@ -21,13 +21,12 @@ import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.history.VcsFileRevision; import com.intellij.openapi.vcs.history.VcsRevisionNumber; import com.intellij.openapi.vfs.VirtualFile; +import git4idea.commands.GitBinaryHandler; import git4idea.commands.GitCommand; -import git4idea.commands.GitSimpleHandler; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.IOException; -import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.util.Date; @@ -94,18 +93,11 @@ public class GitFileRevision implements VcsFileRevision, Comparable myException = new AtomicReference(); + + /** + * A constructor + * + * @param project a project + * @param directory a process directory + * @param command a command to execute (if empty string, the parameter is ignored) + */ + protected GitBinaryHandler(@NotNull Project project, @NotNull File directory, @NotNull GitCommand command) { + super(project, directory, command); + } + + /** + * A constructor + * + * @param project a project + * @param vcsRoot a vcs root + * @param command a command to execute (if empty string, the parameter is ignored) + */ + public GitBinaryHandler(final Project project, final VirtualFile vcsRoot, final GitCommand command) { + super(project, vcsRoot, command); + } + + + /** + * {@inheritDoc} + */ + @Override + protected void startHandlingStreams() { + handleStream(myProcess.getErrorStream(), myStderr); + handleStream(myProcess.getInputStream(), myStdout); + } + + /** + * Handle the single stream + * + * @param in the standard input + * @param out the standard output + */ + private void handleStream(final InputStream in, final ByteArrayOutputStream out) { + Thread t = new Thread(new Runnable() { + @Override + public void run() { + try { + byte[] buffer = new byte[BUFFER_SIZE]; + while (true) { + int rc = 0; + rc = in.read(buffer); + if (rc == -1) { + break; + } + out.write(buffer, 0, rc); + } + } + catch (IOException e) { + //noinspection ThrowableInstanceNeverThrown + if (!myException.compareAndSet(null, new VcsException("Stream IO problem", e))) { + LOG.error("Problem reading stream", e); + } + } + finally { + mySteamSemaphore.release(1); + } + } + }, "Stream copy thread"); + t.setDaemon(true); + t.start(); + } + + /** + * {@inheritDoc} + */ + @Override + protected void destroyProcess() { + myProcess.destroy(); + } + + /** + * {@inheritDoc} + */ + @Override + protected void waitForProcess() { + try { + mySteamSemaphore.acquire(2); + myProcess.waitFor(); + int exitCode = myProcess.exitValue(); + setExitCode(exitCode); + } + catch (InterruptedException e) { + if (LOG.isDebugEnabled()) { + LOG.debug("Ignoring process exception: ", e); + } + setExitCode(255); + } + listeners().processTerminated(getExitCode()); + } + + /** + * Run in the current thread and return the data as array + * + * @return the binary data + * @throws VcsException in case of the problem with running git + */ + public byte[] run() throws VcsException { + addListener(new GitHandlerListener() { + @Override + public void processTerminated(int exitCode) { + if (exitCode != 0 && !isIgnoredErrorCode(exitCode)) { + Charset cs = getCharset(); + cs = cs == null ? GitUtil.UTF8_CHARSET : cs; + String message = new String(myStderr.toByteArray(), cs); + if (message.length() == 0) { + //noinspection ThrowableResultOfMethodCallIgnored + if (myException.get() != null) { + message = "Process finished with exit code " + exitCode; + } + else { + message = null; + } + } + else { + if (!isStderrSuppressed()) { + GitVcs.getInstance(myProject).showErrorMessages(message); + } + } + if (message != null) { + //noinspection ThrowableInstanceNeverThrown + VcsException e = myException.getAndSet(new VcsException(message)); + if (e != null) { + LOG.warn("Dropping previous exception: ", e); + } + } + } + } + + @Override + public void startFailed(Throwable exception) { + //noinspection ThrowableInstanceNeverThrown + VcsException e = myException.getAndSet(new VcsException("Start failed: " + exception.getMessage(), exception)); + if (e != null) { + LOG.warn("Dropping previous exception: ", e); + } + } + }); + GitHandlerUtil.runInCurrentThread(this, null); + //noinspection ThrowableResultOfMethodCallIgnored + if (myException.get() != null) { + throw myException.get(); + } + return myStdout.toByteArray(); + } +} diff --git a/plugins/git4idea/src/git4idea/commands/GitHandler.java b/plugins/git4idea/src/git4idea/commands/GitHandler.java index 1fde79c006a9..3357e4dc4da8 100644 --- a/plugins/git4idea/src/git4idea/commands/GitHandler.java +++ b/plugins/git4idea/src/git4idea/commands/GitHandler.java @@ -73,7 +73,7 @@ public abstract class GitHandler { /** * the context project (might be a default project) */ - private final Project myProject; + final Project myProject; /** * The descriptor for the command to be executed */