blob: 5e66246805d029e07793cd6be896548a6e96533a [file] [log] [blame]
/*
* Copyright 2000-2009 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.ProcessOutputTypes;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vfs.VirtualFile;
import git4idea.i18n.GitBundle;
import org.jetbrains.annotations.NotNull;
import java.io.File;
/**
* Simple Git handler that accumulates stdout and stderr and has nothing on stdin.
* The handler executes commands synchronously with cancellable progress indicator.
* <p/>
* The class also includes a number of static utility methods that represent some
* simple commands.
*/
public class GitSimpleHandler extends GitTextHandler {
public static final String DURING_EXECUTING_ERROR_MESSAGE = "during executing";
/**
* Stderr output
*/
private final StringBuilder myStderr = new StringBuilder();
/**
* Reminder of the last stderr line
*/
private final StringBuilder myStderrLine = new StringBuilder();
/**
* Stdout output
*/
private final StringBuilder myStdout = new StringBuilder();
/**
* Reminder of the last stdout line
*/
private final StringBuilder myStdoutLine = new StringBuilder();
/**
* A constructor
*
* @param project a project
* @param directory a process directory
* @param command a command to execute
*/
@SuppressWarnings({"WeakerAccess"})
public GitSimpleHandler(@NotNull Project project, @NotNull File directory, @NotNull GitCommand command) {
super(project, directory, command);
}
/**
* A constructor
*
* @param project a project
* @param directory a process directory
* @param command a command to execute
*/
@SuppressWarnings({"WeakerAccess"})
public GitSimpleHandler(@NotNull final Project project, @NotNull final VirtualFile directory, @NotNull final GitCommand command) {
super(project, directory, command);
}
/**
* {@inheritDoc}
*/
protected void processTerminated(final int exitCode) {
if (myVcs == null) { return; }
String stdout = myStdoutLine.toString();
String stderr = myStderrLine.toString();
if (!isStdoutSuppressed() && !StringUtil.isEmptyOrSpaces(stdout)) {
myVcs.showMessages(stdout);
LOG.info(stdout.trim());
myStdoutLine.setLength(0);
}
else if (!isStderrSuppressed() && !StringUtil.isEmptyOrSpaces(stderr)) {
myVcs.showErrorMessages(stderr);
LOG.info(stderr.trim());
myStderrLine.setLength(0);
}
else {
LOG.debug(stderr.trim());
OUTPUT_LOG.debug(stdout.trim());
}
}
/**
* For silent handlers, print out everything
*/
public void unsilence() {
if (myVcs == null) { return; }
myVcs.showCommandLine(printableCommandLine());
if (myStderr.length() != 0) {
myVcs.showErrorMessages(myStderr.toString());
}
if (myStdout.length() != 0) {
myVcs.showMessages(myStdout.toString());
}
}
/**
* {@inheritDoc}
*/
protected void onTextAvailable(final String text, final Key outputType) {
final StringBuilder entire;
final StringBuilder lineRest;
final boolean suppressed;
if (ProcessOutputTypes.STDOUT == outputType) {
entire = myStdout;
lineRest = myStdoutLine;
suppressed = isStdoutSuppressed();
}
else if (ProcessOutputTypes.STDERR == outputType) {
entire = myStderr;
lineRest = myStderrLine;
suppressed = isStderrSuppressed();
}
else {
return;
}
entire.append(text);
if (myVcs == null || (suppressed && !LOG.isDebugEnabled())) {
return;
}
int last = lineRest.length() > 0 ? lineRest.charAt(lineRest.length() - 1) : -1;
int start = 0;
for (int i = 0; i < text.length(); i++) {
char ch = text.charAt(i);
if (last == '\n' || last == '\r') {
int savedPos;
if ((ch == '\n' || ch == '\r') && ch != last) {
savedPos = i - 1;
}
else {
savedPos = i;
}
if (last != '\r' || savedPos != i) {
String line;
if (lineRest.length() == 0) {
line = lineRest.append(text.substring(start, savedPos)).toString();
lineRest.setLength(0);
}
else {
line = text.substring(start, savedPos);
}
if (!StringUtil.isEmptyOrSpaces(line)) {
if (!suppressed) {
LOG.info(line.trim());
if (ProcessOutputTypes.STDOUT == outputType) {
myVcs.showMessages(line);
}
else if (ProcessOutputTypes.STDERR == outputType) {
myVcs.showErrorMessages(line);
}
}
else {
LOG.debug(line.trim());
}
}
}
start = savedPos;
}
last = ch;
}
if (start != text.length()) {
lineRest.append(text.substring(start));
}
}
/**
* @return stderr contents
*/
public String getStderr() {
return myStderr.toString();
}
/**
* @return stdout contents
*/
public String getStdout() {
return myStdout.toString();
}
/**
* Execute without UI. If UI interactions are required (for example SSH popups or progress dialog), use {@link GitHandlerUtil} methods.
*
* @return a value if process was successful
* @throws VcsException exception if process failed to start.
*/
public String run() throws VcsException {
if (isRemote()) {
throw new IllegalStateException("Commands that require remote access could not be run using this method");
}
final VcsException[] ex = new VcsException[1];
final String[] result = new String[1];
addListener(new GitHandlerListener() {
public void processTerminated(final int exitCode) {
try {
if (exitCode == 0 || isIgnoredErrorCode(exitCode)) {
result[0] = getStdout();
}
else {
String msg = getStderr();
if (msg.length() == 0) {
msg = getStdout();
}
if (msg.length() == 0) {
msg = GitBundle.message("git.error.exit", exitCode);
}
ex[0] = new VcsException(msg);
}
}
catch (Throwable t) {
ex[0] = new VcsException(t.toString(), t);
}
}
public void startFailed(final Throwable exception) {
ex[0] = new VcsException("Process failed to start (" + myCommandLine.getCommandLineString() + "): " + exception.toString(), exception);
}
});
runInCurrentThread(null);
if (ex[0] != null) {
throw new VcsException(ex[0].getMessage() + " " + DURING_EXECUTING_ERROR_MESSAGE + " " + printableCommandLine(), ex[0]);
}
if (result[0] == null) {
throw new VcsException("The git command returned null: " + printableCommandLine());
}
return result[0];
}
}