blob: 62aabee3a3bc0d3e44e4d0ffe3436b920c380bd0 [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.rebase;
import com.intellij.execution.process.ProcessOutputTypes;
import com.intellij.openapi.util.Key;
import git4idea.commands.GitLineHandlerAdapter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* This listener gathers information relevant to the progress of the rebase operation
*/
public class GitRebaseLineListener extends GitLineHandlerAdapter {
/**
* Git rebase progress message
*/
private static final Pattern PROGRESS = Pattern.compile("^Rebasing \\((\\d+)/(\\d+)\\)$");
/**
* The status
*/
private Status myStatus;
/**
* The progress line
*/
private String myProgressLine;
/**
* {@inheritDoc}
*/
@Override
public synchronized void onLineAvailable(String line, Key outputType) {
if (outputType == ProcessOutputTypes.STDOUT) {
if (PROGRESS.matcher(line).matches()) {
myProgressLine = line;
// a bit dodgy line since STDERR line could arrive before STDOUT line,
// but in practice STDOUT comes first.
myStatus = null;
}
}
else {
if (line.startsWith("You can amend the commit now")) {
assert myStatus == null;
myStatus = Status.EDIT;
}
else if (line.startsWith("Successfully rebased and updated")) {
assert myStatus == null;
myStatus = Status.FINISHED;
}
else if (line.startsWith("Automatic cherry-pick failed") || line.startsWith("When you have resolved this problem")) {
assert myStatus == null || myStatus == Status.ERROR;
myStatus = Status.CONFLICT;
}
else if (line.startsWith("Could not execute editor")) {
assert myStatus == null;
myStatus = myProgressLine == null ? Status.CANCELLED : Status.ERROR;
}
else if (line.startsWith("fatal") || line.startsWith("error: ") || line.startsWith("Cannot rebase")) {
if (myStatus != Status.CONFLICT) {
myStatus = Status.ERROR;
}
}
}
}
/**
* @return the progress values as a pair
*/
public synchronized Result getResult() {
int total;
int current;
if (myProgressLine != null) {
// the integers already matched the digits pattern, so they should parse
final Matcher matcher = PROGRESS.matcher(myProgressLine);
if (matcher.matches()) {
current = Integer.parseInt(matcher.group(1));
total = Integer.parseInt(matcher.group(2));
}
else {
throw new IllegalStateException("The wrong current result line: " + myProgressLine);
}
}
else {
total = current = 0;
}
return new Result(myStatus == null ? Status.FINISHED : myStatus, total, current);
}
/**
* The result of operation
*/
public static final class Result {
/**
* The operation status
*/
public final Status status;
/**
* The total number of commits
*/
public final int total;
/**
* The commit number that is being currently processed
*/
public final int current;
/**
* A constructor
*
* @param status the status
* @param total the commit count
* @param current the current commit
*/
public Result(Status status, int total, int current) {
this.status = status;
this.total = total;
this.current = current;
}
}
/**
* The current rebase status
*/
public enum Status {
/**
* Rebase operation is cancelled (could not execute editor)
*/
CANCELLED,
/**
* Rebase is finished
*/
FINISHED,
/**
* Suspended for edit
*/
EDIT,
/**
* Suspended due to the conflict
*/
CONFLICT,
/**
* Suspended due to the error
*/
ERROR
}
}