[git] do not mix normal output with error output; check exit code before parsing remaining buffer on process terminated

EA-90861
This commit is contained in:
Julia Beliaeva
2016-10-30 19:41:26 +03:00
parent 44583db831
commit c0d85551ac
@@ -15,6 +15,7 @@
*/
package git4idea.history;
import com.intellij.execution.process.ProcessOutputTypes;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
@@ -55,6 +56,7 @@ import git4idea.history.browser.SHAHash;
import git4idea.history.browser.SymbolicRefs;
import git4idea.history.browser.SymbolicRefsI;
import git4idea.history.wholeTree.AbstractHash;
import git4idea.i18n.GitBundle;
import git4idea.log.GitLogProvider;
import git4idea.log.GitRefManager;
import org.jetbrains.annotations.NotNull;
@@ -537,70 +539,85 @@ public class GitHistoryUtils {
@NotNull Consumer<StringBuilder> recordConsumer,
int bufferSize)
throws VcsException {
final StringBuilder buffer = new StringBuilder();
final StringBuilder output = new StringBuilder();
final StringBuilder errors = new StringBuilder();
final Ref<Boolean> foundRecordEnd = Ref.create(false);
final Ref<VcsException> ex = new Ref<>();
final AtomicInteger records = new AtomicInteger();
handler.addLineListener(new GitLineHandlerListener() {
@Override
public void onLineAvailable(String line, Key outputType) {
try {
// format of the record is <RECORD_START>.*<RECORD_END>.*
// then next record goes
// (rather inconveniently, after RECORD_END there is a list of modified files)
// so here I'm trying to find text between two RECORD_START symbols
// that simultaneously contains a RECORD_END
// this helps to deal with commits like a929478f6720ac15d949117188cd6798b4a9c286 in linux repo that have RECORD_START symbols in the message
// wont help with RECORD_END symbols in the message however (have not seen those yet)
String tail = null;
if (!foundRecordEnd.get()) {
int recordEnd = line.indexOf(GitLogParser.RECORD_END);
if (recordEnd != -1) {
foundRecordEnd.set(true);
buffer.append(line.substring(0, recordEnd + 1));
line = line.substring(recordEnd + 1);
}
else {
buffer.append(line).append("\n");
}
}
if (foundRecordEnd.get()) {
int nextRecordStart = line.indexOf(GitLogParser.RECORD_START);
if (nextRecordStart == -1) {
buffer.append(line).append("\n");
}
else if (nextRecordStart == 0) {
tail = line + "\n";
}
else {
buffer.append(line.substring(0, nextRecordStart));
tail = line.substring(nextRecordStart) + "\n";
}
}
if (tail != null) {
if (records.incrementAndGet() > bufferSize) {
recordConsumer.consume(buffer);
buffer.setLength(0);
}
buffer.append(tail);
foundRecordEnd.set(false);
}
if (outputType == ProcessOutputTypes.STDERR) {
errors.append(line).append("\n");
}
catch (Exception e) {
ex.set(new VcsException(e));
else if (outputType == ProcessOutputTypes.STDOUT) {
try {
// format of the record is <RECORD_START>.*<RECORD_END>.*
// then next record goes
// (rather inconveniently, after RECORD_END there is a list of modified files)
// so here I'm trying to find text between two RECORD_START symbols
// that simultaneously contains a RECORD_END
// this helps to deal with commits like a929478f6720ac15d949117188cd6798b4a9c286 in linux repo that have RECORD_START symbols in the message
// wont help with RECORD_END symbols in the message however (have not seen those yet)
String tail = null;
if (!foundRecordEnd.get()) {
int recordEnd = line.indexOf(GitLogParser.RECORD_END);
if (recordEnd != -1) {
foundRecordEnd.set(true);
output.append(line.substring(0, recordEnd + 1));
line = line.substring(recordEnd + 1);
}
else {
output.append(line).append("\n");
}
}
if (foundRecordEnd.get()) {
int nextRecordStart = line.indexOf(GitLogParser.RECORD_START);
if (nextRecordStart == -1) {
output.append(line).append("\n");
}
else if (nextRecordStart == 0) {
tail = line + "\n";
}
else {
output.append(line.substring(0, nextRecordStart));
tail = line.substring(nextRecordStart) + "\n";
}
}
if (tail != null) {
if (records.incrementAndGet() > bufferSize) {
recordConsumer.consume(output);
output.setLength(0);
}
output.append(tail);
foundRecordEnd.set(false);
}
}
catch (Exception e) {
ex.set(new VcsException(e));
}
}
}
@Override
public void processTerminated(int exitCode) {
try {
recordConsumer.consume(buffer);
if (exitCode != 0) {
String errorMessage = errors.toString();
if (errorMessage.isEmpty()) {
errorMessage = GitBundle.message("git.error.exit", exitCode);
}
ex.set(new VcsException(errorMessage));
}
catch (Exception e) {
ex.set(new VcsException(e));
else {
try {
recordConsumer.consume(output);
}
catch (Exception e) {
ex.set(new VcsException(e));
}
}
}