mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
git4idea: Added binary process handler and made use of it for getting file content
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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<VcsFileRevis
|
||||
|
||||
public synchronized void loadContent() throws VcsException {
|
||||
final VirtualFile root = GitUtil.getGitRoot(path);
|
||||
GitSimpleHandler h = new GitSimpleHandler(project, root, GitCommand.SHOW);
|
||||
GitBinaryHandler h = new GitBinaryHandler(project, root, GitCommand.SHOW);
|
||||
h.setNoSSH(true);
|
||||
h.setCharset(BIN_ENCODING);
|
||||
h.setSilent(true);
|
||||
h.addParameters(revision.getRev() + ":" + GitUtil.relativePath(root, path));
|
||||
String result = h.run();
|
||||
try {
|
||||
content = result.getBytes(BIN_ENCODING.name());
|
||||
}
|
||||
catch (UnsupportedEncodingException e) {
|
||||
throw new VcsException("Unable to locate encoding: " + BIN_ENCODING.name() + " Reason: " + e.toString(), e);
|
||||
}
|
||||
content = h.run();
|
||||
}
|
||||
|
||||
public synchronized byte[] getContent() throws IOException {
|
||||
|
||||
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* 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.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import git4idea.GitUtil;
|
||||
import git4idea.GitVcs;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* The handler that allows consuming binary data as byte array
|
||||
*/
|
||||
public class GitBinaryHandler extends GitHandler {
|
||||
/**
|
||||
* The logger
|
||||
*/
|
||||
private static final Logger LOG = Logger.getInstance(GitBinaryHandler.class.getName());
|
||||
/**
|
||||
* Stdout stream
|
||||
*/
|
||||
private final ByteArrayOutputStream myStdout = new ByteArrayOutputStream();
|
||||
/**
|
||||
* Stderr stream
|
||||
*/
|
||||
private final ByteArrayOutputStream myStderr = new ByteArrayOutputStream();
|
||||
/**
|
||||
* The semaphore that waits for stream processing
|
||||
*/
|
||||
private final Semaphore mySteamSemaphore = new Semaphore(0);
|
||||
/**
|
||||
* The size of buffer to use
|
||||
*/
|
||||
private static final int BUFFER_SIZE = 8 * 1024;
|
||||
/**
|
||||
* The exception to use
|
||||
*/
|
||||
private AtomicReference<VcsException> myException = new AtomicReference<VcsException>();
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user