package zielu.gittoolbox.status; import com.google.common.base.Preconditions; import com.google.common.collect.Maps; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.EmptyProgressIndicator; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; import com.intellij.vcs.log.Hash; import git4idea.GitLocalBranch; import git4idea.GitUtil; import git4idea.commands.GitCommand; import git4idea.commands.GitLineHandler; import git4idea.commands.GitTask; import git4idea.commands.GitTaskResultHandlerAdapter; import git4idea.repo.GitBranchTrackInfo; import git4idea.repo.GitRepository; import java.util.Collection; import java.util.Map; import java.util.Optional; import java.util.concurrent.atomic.AtomicReference; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public class GitStatusCalculator { private final Logger LOG = Logger.getInstance(getClass()); private final Project myProject; private final ProgressIndicator myIndicator; private GitStatusCalculator(Project project, ProgressIndicator indicator) { myProject = Preconditions.checkNotNull(project); myIndicator = Preconditions.checkNotNull(indicator); } public static GitStatusCalculator create(@NotNull Project project, @NotNull ProgressIndicator indicator) { return new GitStatusCalculator(project, indicator); } public static GitStatusCalculator create(@NotNull Project project) { return create(project, new EmptyProgressIndicator()); } public Map<GitRepository, RevListCount> behindStatus(Collection<GitRepository> repositories) { Map<GitRepository, RevListCount> result = Maps.newLinkedHashMap(); for (GitRepository repository : repositories) { result.put(repository, behindStatus(repository)); } return result; } @NotNull public RevListCount behindStatus(GitRepository repository) { Optional<GitBranchTrackInfo> trackInfo = trackInfoForCurrentBranch(repository); if (trackInfo.isPresent()) { return behindStatus(repository.getCurrentBranch(), trackInfo.get(), repository); } return RevListCount.noRemote(); } @NotNull public GitAheadBehindCount aheadBehindStatus(@NotNull GitRepository repository) { Optional<GitBranchTrackInfo> trackInfo = trackInfoForCurrentBranch(repository); if (trackInfo.isPresent()) { return aheadBehindStatus(repository.getCurrentBranch(), trackInfo.get(), repository); } return GitAheadBehindCount.noRemote(); } public GitAheadBehindCount aheadBehindStatus(@NotNull GitRepository repository, @Nullable Hash localHash, @Nullable Hash remoteHash) { if (localHash != null && remoteHash != null) { return doRevListLeftRight(localHash.asString(), remoteHash.asString(), repository); } else { return GitAheadBehindCount.noRemote(); } } private RevListCount behindStatus(GitLocalBranch currentBranch, GitBranchTrackInfo trackInfo, GitRepository repository) { String localName = currentBranch.getName(); String remoteName = trackInfo.getRemoteBranch().getNameForLocalOperations(); GitAheadBehindCount count = doRevListLeftRight(localName, remoteName, repository); return count.behind; } private Optional<GitBranchTrackInfo> trackInfoForCurrentBranch(GitRepository repository) { GitBranchTrackInfo trackInfo = GitUtil.getTrackInfoForCurrentBranch(repository); return Optional.ofNullable(trackInfo); } private GitAheadBehindCount aheadBehindStatus( GitLocalBranch localBranch, GitBranchTrackInfo trackInfo, GitRepository repository) { String localName = localBranch.getName(); String remoteName = trackInfo.getRemoteBranch().getNameForLocalOperations(); return doRevListLeftRight(localName, remoteName, repository); } @NotNull private GitAheadBehindCount doRevListLeftRight(String localRef, String remoteRef, GitRepository repository) { final boolean debug = LOG.isDebugEnabled(); String branches = localRef + "..." + remoteRef; final GitLineHandler handler = new GitLineHandler(myProject, repository.getRoot(), GitCommand.REV_LIST); handler.addParameters(branches, "--left-right"); final GitRevListLeftRightCounter counter = new GitRevListLeftRightCounter(); handler.addLineListener(counter); GitTask task = new GitTask(myProject, handler, branches); task.setProgressIndicator(myIndicator); final AtomicReference<GitAheadBehindCount> result = new AtomicReference<GitAheadBehindCount>(); if (debug) { LOG.debug("Executing count with refs: '" + branches + "'"); } task.execute(true, false, new GitTaskResultHandlerAdapter() { @Override protected void onSuccess() { result.set(GitAheadBehindCount.success(counter.ahead(), counter.aheadTop(), counter.behind(), counter.behindTop())); } @Override protected void onCancel() { result.set(GitAheadBehindCount.cancel()); } @Override protected void onFailure() { result.set(GitAheadBehindCount.failure()); } }); return Preconditions.checkNotNull(result.get(), "Null rev list left right"); } }