package zielu.gittoolbox.cache; import com.google.common.base.Objects; import com.intellij.openapi.diagnostic.Logger; import git4idea.repo.GitRepository; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import zielu.gittoolbox.status.GitAheadBehindCount; import zielu.gittoolbox.status.GitStatusCalculator; import zielu.gittoolbox.util.GtUtil; import zielu.gittoolbox.util.LogWatch; class CachedStatus { private static final Logger LOG = Logger.getInstance(CachedStatus.class); private final LogWatch repoStatusCreateWatch = LogWatch.create(LOG, "Repo status create"); private final AtomicBoolean myInvalid = new AtomicBoolean(true); private final AtomicBoolean myNew = new AtomicBoolean(true); private final AtomicReference<RepoInfo> myInfo = new AtomicReference<>(RepoInfo.empty()); private final String myRepoName; @Nullable private GitAheadBehindCount myCount; private RepoStatus myStatus; private CachedStatus(String repoName) { myRepoName = repoName; } public static CachedStatus create(GitRepository repository) { return new CachedStatus(GtUtil.name(repository)); } @NotNull public synchronized void update(@NotNull GitRepository repo, @NotNull GitStatusCalculator calculator, @NotNull Consumer<RepoInfo> infoConsumer) { final boolean debug = LOG.isDebugEnabled(); myNew.set(false); if (myInvalid.get()) { repoStatusCreateWatch.start(); RepoStatus currentStatus = RepoStatus.create(repo); repoStatusCreateWatch.finish(); if (debug) { LOG.debug("State update [" + myRepoName + "]:\nnew=" + currentStatus + "\nold=" + myStatus); } if (!Objects.equal(myStatus, currentStatus)) { GitAheadBehindCount oldCount = myCount; LogWatch statusUpdateWatch = LogWatch.createStarted(LOG, "Status update"); myCount = calculator.aheadBehindStatus(repo, currentStatus.localHash(), currentStatus.remoteHash()); statusUpdateWatch.finish(); if (debug) { LOG.debug("Updated stale status [" + myRepoName + "]: " + oldCount + " > " + myCount); } if (!currentStatus.sameHashes(myCount)) { LOG.warn("Hash mismatch between count and status: " + myCount + " <> " + currentStatus); } myStatus = currentStatus; RepoInfo newInfo = RepoInfo.create(myStatus, myCount); myInfo.set(newInfo); myInvalid.set(false); infoConsumer.accept(newInfo); } else { if (debug) { LOG.debug("Status did not change [" + myRepoName + "]: " + myCount); } } } else { if (debug) { LOG.debug("Status is still valid [" + myRepoName + "]: " + myCount); } } } public void invalidate() { myInvalid.set(true); } public boolean isInvalid() { return myInvalid.get(); } public boolean isNew() { return myNew.get(); } @NotNull public RepoInfo get() { return myInfo.get(); } }