package com.beijunyi.parallelgit.filesystem.commands;
import java.io.IOException;
import java.text.MessageFormat;
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.NoBranchException;
import com.beijunyi.parallelgit.filesystem.exceptions.NoHeadCommitException;
import com.beijunyi.parallelgit.filesystem.exceptions.UnsuccessfulOperationException;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.revwalk.RevCommit;
import static com.beijunyi.parallelgit.filesystem.commands.GfsCreateStash.Result.*;
import static com.beijunyi.parallelgit.filesystem.commands.GfsCreateStash.Status.*;
import static com.beijunyi.parallelgit.utils.CommitUtils.*;
import static com.beijunyi.parallelgit.utils.StashUtils.addToStash;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static org.eclipse.jgit.lib.Repository.shortenRefName;
public class GfsCreateStash extends GfsCommand<GfsCreateStash.Result> {
private static final String DEFAULT_INDEX_MESSAGE_FORMAT = "index on {0}: {1} {2}";
private static final String DEFAULT_WORKING_DIR_MESSAGE_FORMAT = "WIP on {0}: {1} {2}";
private String branch;
private String indexMessage;
private String workingDirectoryMessage;
private PersonIdent committer;
private RevCommit parent;
public GfsCreateStash(GitFileSystem gfs) {
super(gfs);
}
@Nonnull
public GfsCreateStash indexMessage(String message) {
this.indexMessage = message;
return this;
}
@Nonnull
public GfsCreateStash workingDirectoryMessage(String message) {
this.workingDirectoryMessage = message;
return this;
}
@Nonnull
public GfsCreateStash committer(PersonIdent committer) {
this.committer = committer;
return this;
}
@Nonnull
@Override
protected GfsCreateStash.Result doExecute(GfsStatusProvider.Update update) throws IOException {
prepareBranch();
prepareCommitter();
prepareParent();
prepareIndexMessage();
prepareDirectoryMessage();
AnyObjectId resultTree = gfs.flush();
GfsCreateStash.Result result;
if(parent != null && parent.getTree().equals(resultTree)) {
result = noChange();
} else {
RevCommit indexCommit = makeIndexCommit(resultTree);
RevCommit stashCommit = makeWorkingDirectoryCommit(indexCommit);
addToStash(stashCommit, repo);
result = success(stashCommit);
}
return result;
}
private void prepareBranch() {
if(!status.isAttached()) throw new NoBranchException();
branch = shortenRefName(status.branch());
}
private void prepareCommitter() {
if(committer == null) committer = new PersonIdent(repo);
}
private void prepareParent() {
if(!status.isInitialized()) throw new NoHeadCommitException();
parent = status.commit();
}
private void prepareIndexMessage() throws IOException {
if(indexMessage == null)
indexMessage = MessageFormat.format(DEFAULT_INDEX_MESSAGE_FORMAT, branch, parent.abbreviate(7).name(), getCommit(parent, repo).getShortMessage());
}
private void prepareDirectoryMessage() throws IOException {
if(workingDirectoryMessage == null)
workingDirectoryMessage = MessageFormat.format(DEFAULT_WORKING_DIR_MESSAGE_FORMAT, branch, parent.abbreviate(7).name(), getCommit(parent, repo).getShortMessage());
}
@Nonnull
private RevCommit makeIndexCommit(AnyObjectId tree) throws IOException {
List<RevCommit> parents = singletonList(parent);
return createCommit(indexMessage, tree, committer, committer, parents, repo);
}
@Nonnull
private RevCommit makeWorkingDirectoryCommit(RevCommit indexCommit) throws IOException {
AnyObjectId tree = indexCommit.getTree();
List<RevCommit> parents = asList(parent, indexCommit);
return createCommit(workingDirectoryMessage, tree, committer, committer, parents, repo);
}
public enum Status {
COMMITTED,
NO_CHANGE
}
public static class Result implements GfsCommandResult {
private final Status status;
private final RevCommit commit;
public Result(Status status, @Nullable RevCommit commit) {
this.status = status;
this.commit = commit;
}
@Nonnull
public static Result success(RevCommit commit) {
return new Result(COMMITTED, commit);
}
@Nonnull
public static Result noChange() {
return new Result(NO_CHANGE, null);
}
@Override
public boolean isSuccessful() {
return COMMITTED.equals(status);
}
@Nonnull
public RevCommit getCommit() {
if(commit == null)
throw new UnsuccessfulOperationException();
return commit;
}
}
}