package zielu.gittoolbox.fetch;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.Task.Backgroundable;
import com.intellij.openapi.project.Project;
import git4idea.GitUtil;
import git4idea.GitVcs;
import git4idea.repo.GitRepository;
import git4idea.repo.GitRepositoryManager;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import org.jetbrains.annotations.NotNull;
import zielu.gittoolbox.GitToolBoxConfigForProject;
import zielu.gittoolbox.GitToolBoxProject;
import zielu.gittoolbox.ResBundle;
import zielu.gittoolbox.compat.NotificationHandle;
import zielu.gittoolbox.compat.Notifier;
import zielu.gittoolbox.ui.util.AppUtil;
public class AutoFetchTask implements Runnable {
private static final boolean showNotifications = false;
private final Logger LOG = Logger.getInstance(getClass());
private final AutoFetch myParent;
private final Project myProject;
private final AtomicReference<NotificationHandle> lastNotification = new AtomicReference<NotificationHandle>();
private AutoFetchTask(AutoFetch parent) {
myParent = parent;
myProject = myParent.project();
}
public static AutoFetchTask create(AutoFetch parent) {
return new AutoFetchTask(parent);
}
private void finishedNotification() {
NotificationHandle toCancel = lastNotification.getAndSet(null);
if (toCancel != null && myParent.isActive()) {
toCancel.expire();
}
if (myParent.isActive()) {
NotificationHandle notification = Notifier.getInstance(myProject).notifyLogOnly(
ResBundle.getString("message.autoFetch"),
ResBundle.getString("message.finished"));
lastNotification.set(notification);
}
}
private void finishedWithoutFetch() {
NotificationHandle toCancel = lastNotification.getAndSet(null);
if (toCancel != null && myParent.isActive()) {
toCancel.expire();
}
}
private List<GitRepository> reposForFetch() {
GitRepositoryManager repositoryManager = GitUtil.getRepositoryManager(myProject);
ImmutableList<GitRepository> allRepos = ImmutableList.copyOf(repositoryManager.getRepositories());
AutoFetchStrategy strategy = GitToolBoxConfigForProject.getInstance(myProject).getAutoFetchStrategy();
List<GitRepository> fetchable = strategy.fetchableRepositories(allRepos, myProject);
List<GitRepository> toFetch = Lists.newArrayListWithCapacity(fetchable.size());
for (GitRepository repository : fetchable) {
if (repository.getRoot().exists() && !repository.isRebaseInProgress()) {
toFetch.add(repository);
}
}
return toFetch;
}
private boolean doFetch(List<GitRepository> repos, @NotNull ProgressIndicator indicator, @NotNull String title) {
LOG.debug("Starting auto-fetch...");
boolean result = false;
AutoFetchState state = AutoFetchState.getInstance(myProject);
if (state.canAutoFetch()) {
LOG.debug("Can auto-fetch");
if (state.fetchStart()) {
indicator.setText(title);
indicator.setIndeterminate(true);
indicator.startNonCancelableSection();
try {
doFetch(repos, indicator);
} finally {
indicator.finishNonCancelableSection();
state.fetchFinish();
myParent.updateLastAutoFetchDate();
}
} else {
LOG.info("Auto-fetch already in progress");
finishedWithoutFetch();
}
result = true;
} else {
LOG.debug("Auto-fetch inactive");
finishedWithoutFetch();
}
return result;
}
private void doFetch(List<GitRepository> repos, @NotNull ProgressIndicator indicator) {
LOG.debug("Auto-fetching...");
Collection<GitRepository> fetched = GtFetcher.builder().fetchAll().build(myProject, indicator).fetchRoots(repos);
GitToolBoxProject.getInstance(myProject).perRepoStatusCache().refresh(fetched);
LOG.debug("Finished auto-fetch");
if (showNotifications) {
finishedNotification();
}
}
@Override
public void run() {
final List<GitRepository> repos = reposForFetch();
boolean shouldFetch = !repos.isEmpty();
if (shouldFetch) {
AppUtil.invokeLaterIfNeeded(() -> GitVcs.runInBackground(new Backgroundable(Preconditions.checkNotNull(myProject),
ResBundle.getString("message.autoFetching"), false) {
@Override
public void run(@NotNull ProgressIndicator indicator) {
if (doFetch(repos, indicator, getTitle())) {
myParent.scheduleNextTask();
}
}
}));
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("Fetched skipped: shouldFetch=" + shouldFetch);
}
if (showNotifications) {
AppUtil.invokeLaterIfNeeded(this::finishedWithoutFetch);
}
}
}
}