package com.beijunyi.parallelgit.filesystem.commands;
import java.io.IOException;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import com.beijunyi.parallelgit.filesystem.GfsStatusProvider;
import com.beijunyi.parallelgit.filesystem.GitFileSystem;
import com.beijunyi.parallelgit.filesystem.exceptions.UnsuccessfulOperationException;
import com.beijunyi.parallelgit.filesystem.merge.MergeNote;
import com.beijunyi.parallelgit.utils.BranchUtils;
import com.beijunyi.parallelgit.utils.CommitUtils;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.revwalk.RevCommit;
import static java.util.Arrays.asList;
import static java.util.Collections.*;
public class GfsCommit extends GfsCommand<GfsCommit.Result> {
private PersonIdent author;
private PersonIdent committer;
private String message;
private List<? extends AnyObjectId> parents;
private boolean amend = false;
private boolean allowEmpty = false;
public GfsCommit(GitFileSystem gfs) {
super(gfs);
}
@Nonnull
@Override
protected Result doExecute(GfsStatusProvider.Update update) throws IOException {
prepareMessage();
prepareCommitter();
prepareAuthor();
prepareParents();
ObjectId resultTree = gfs.flush();
gfs.updateOrigin(resultTree);
if(!allowEmpty && !amend && isSameAsParent(resultTree))
return Result.noChange();
RevCommit resultCommit = CommitUtils.createCommit(message, resultTree, author, committer, parents, repo);
updateStatus(update, resultCommit);
return Result.success(resultCommit);
}
@Nonnull
public GfsCommit author(@Nullable PersonIdent author) {
this.author = author;
return this;
}
@Nonnull
public GfsCommit committer(@Nullable PersonIdent committer) {
this.committer = committer;
return this;
}
@Nonnull
public GfsCommit message(@Nullable String message) {
this.message = message;
return this;
}
@Nonnull
public GfsCommit amend(boolean amend) {
this.amend = amend;
return this;
}
@Nonnull
public GfsCommit allowEmpty(boolean allowEmpty) {
this.allowEmpty = allowEmpty;
return this;
}
private void prepareMessage() {
if(message == null) {
MergeNote note = status.mergeNote();
message = note != null ? note.getMessage() : "";
}
}
private void prepareCommitter() {
if(committer == null) committer = new PersonIdent(repo);
}
private void prepareAuthor() {
if(author == null) {
if(!amend)
author = committer;
else
author = status.commit().getAuthorIdent();
}
}
private void prepareParents() {
if(parents == null) {
if(!amend) {
MergeNote mergeNote = status.mergeNote();
if(mergeNote != null && mergeNote.getSource() != null) {
parents = asList(status.commit(), mergeNote.getSource());
} else if(status.isInitialized()) {
parents = singletonList(status.commit());
} else {
parents = emptyList();
}
} else {
parents = asList(status.commit().getParents());
}
}
}
private boolean isSameAsParent(AnyObjectId newTree) {
return status.isInitialized() && status.commit().getTree().equals(newTree);
}
private void updateStatus(GfsStatusProvider.Update update, RevCommit newHead) throws IOException {
if(status.isAttached()) {
MergeNote mergeNote = status.mergeNote();
if(!amend) {
if(mergeNote != null) {
BranchUtils.mergeCommit(status.branch(), newHead, repo);
} else if(status.isInitialized()) {
BranchUtils.newCommit(status.branch(), newHead, repo);
} else {
BranchUtils.initBranch(status.branch(), newHead, repo);
}
} else {
BranchUtils.amendCommit(status.branch(), newHead, repo);
}
}
update.commit(newHead);
update.clearMergeNote();
}
public enum Status {
COMMITTED,
NO_CHANGE
}
public static class Result implements GfsCommandResult {
private final Status status;
private final RevCommit commit;
private Result(Status status, @Nullable RevCommit commit) {
this.status = status;
this.commit = commit;
}
@Nonnull
public static Result success(RevCommit commit) {
return new Result(Status.COMMITTED, commit);
}
@Nonnull
public static Result noChange() {
return new Result(Status.NO_CHANGE, null);
}
@Override
public boolean isSuccessful() {
return commit != null;
}
@Nonnull
public RevCommit getCommit() {
if(commit == null) throw new UnsuccessfulOperationException();
return commit;
}
@Nonnull
public Status getStatus() {
return status;
}
}
}