package com.beijunyi.parallelgit.filesystem.commands; import java.io.IOException; import java.util.Collections; import java.util.Map; import javax.annotation.Nonnull; import com.beijunyi.parallelgit.filesystem.GfsStatusProvider; import com.beijunyi.parallelgit.filesystem.GitFileSystem; import com.beijunyi.parallelgit.filesystem.exceptions.NoBranchException; import com.beijunyi.parallelgit.filesystem.io.GfsCheckoutConflict; import com.beijunyi.parallelgit.filesystem.io.GfsDefaultCheckout; import com.beijunyi.parallelgit.utils.BranchUtils; import com.beijunyi.parallelgit.utils.CommitUtils; import com.beijunyi.parallelgit.utils.RefUtils; import com.beijunyi.parallelgit.utils.exceptions.NoSuchBranchException; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.revwalk.RevCommit; import static java.util.Collections.unmodifiableMap; public class GfsCheckout extends GfsCommand<GfsCheckout.Result> { private String target; private boolean force = false; private boolean detach = false; private String targetBranch; private RevCommit targetCommit; public GfsCheckout(GitFileSystem gfs) { super(gfs); } @Nonnull @Override protected Result doExecute(GfsStatusProvider.Update update) throws IOException { prepareFileSystem(); prepareTarget(); GfsDefaultCheckout checkout = new GfsDefaultCheckout(gfs, false); checkout.checkout(targetCommit.getTree()); if(checkout.hasConflicts()) return Result.checkoutConflicts(checkout.getConflicts()); store.getRoot().updateOrigin(targetCommit.getTree()); updateHead(update); return Result.success(); } @Nonnull public GfsCheckout target(String target) { this.target = target; return this; } @Nonnull public GfsCheckout force(boolean force) { this.force = force; return this; } @Nonnull public GfsCheckout detach(boolean detach) { this.detach = detach; return this; } private void prepareFileSystem() { if(force) store.getRoot().reset(); } private void prepareTarget() throws IOException { if(target == null) throw new NoBranchException(); if(!detach) { if(BranchUtils.branchExists(target, repo)) { Ref branchRef = RefUtils.getBranchRef(target, repo); targetBranch = branchRef.getName(); targetCommit = CommitUtils.getCommit(targetBranch, repo); } } if(targetCommit == null) { if(CommitUtils.exists(target, repo)) targetCommit = CommitUtils.getCommit(target, repo); else throw new NoSuchBranchException(target); } } private void updateHead(GfsStatusProvider.Update update) { if(targetBranch == null) update.detach(); else update.branch(targetBranch); update.commit(targetCommit); } public static class Result implements GfsCommandResult { private final boolean successful; private final Map<String, GfsCheckoutConflict> conflicts; private Result(boolean successful, Map<String, GfsCheckoutConflict> conflicts) { this.successful = successful; this.conflicts = unmodifiableMap(conflicts); } @Nonnull public static Result success() { return new Result(true, Collections.<String, GfsCheckoutConflict>emptyMap()); } @Nonnull public static Result checkoutConflicts(Map<String, GfsCheckoutConflict> conflicts) { return new Result(false, conflicts); } @Override public boolean isSuccessful() { return successful; } public boolean hasConflicts() { return !conflicts.isEmpty(); } @Nonnull public Map<String, GfsCheckoutConflict> getConflicts() { return conflicts; } } }