[vcs] get rid of Continuation in PatchApplier, shelve and GitUpdateProcess

Substitute it with a more clear control flow.

* PatchApplier: make ApplyPatchTask synchronous: it is executed from the EDT,
  so update the ChangeListManager in SYNCHRONOUS mode (modal task).

* ShelveChangesManager: make unshelveChangeList synchronous as well,
  surround the part which needs to be called from the EDT by invokeAndWait.

* GitUpdateProcess: substitute GitComplexProcess (which is continuation-based)
  with GitFreezingProcess (which does the same about blocking and freezing,
  but without the continuation logic).

* GitStashChangesSaver#load doesn't actually throw a VcsException => remove
This commit is contained in:
Kirill Likhodedov
2015-07-24 16:17:19 +03:00
parent d469b41386
commit af5a1460fe
11 changed files with 108 additions and 214 deletions
@@ -26,7 +26,6 @@ import com.intellij.openapi.diff.impl.patch.apply.ApplyTextFilePatch;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypes;
import com.intellij.openapi.fileTypes.ex.FileTypeChooser;
import com.intellij.openapi.progress.AsynchronousExecution;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.ui.Messages;
@@ -43,11 +42,10 @@ import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Consumer;
import com.intellij.util.WaitForProgressToShow;
import com.intellij.util.continuation.*;
import com.intellij.vcsUtil.VcsUtil;
import org.jetbrains.annotations.CalledInAwt;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.CalledInAwt;
import java.io.IOException;
import java.util.*;
@@ -127,23 +125,12 @@ public class PatchApplier<BinaryType extends FilePatch> {
return new FilesMover(clm, targetChangeList);
}
@AsynchronousExecution
@CalledInAwt
public void execute() {
execute(true);
execute(true, false);
}
@AsynchronousExecution
public void execute(boolean showSuccessNotification) {
final Continuation continuation = ApplicationManager.getApplication().isDispatchThread() ?
Continuation.createFragmented(myProject, true) :
Continuation.createForCurrentProgress(myProject, true);
final GatheringContinuationContext initContext =
new GatheringContinuationContext();
scheduleSelf(showSuccessNotification, initContext, false);
continuation.run(initContext.getList());
}
public class ApplyPatchTask extends TaskDescriptor {
public class ApplyPatchTask {
private ApplyPatchStatus myStatus;
private final boolean myShowNotification;
private final boolean mySystemOperation;
@@ -151,14 +138,12 @@ public class PatchApplier<BinaryType extends FilePatch> {
private VcsShowConfirmationOption.Value myDeleteconfirmationvalue;
public ApplyPatchTask(final boolean showNotification, boolean systemOperation) {
super("", Where.AWT);
myShowNotification = showNotification;
mySystemOperation = systemOperation;
}
@CalledInAwt
@Override
public void run(ContinuationContext context) {
public void run() {
myRemainingPatches.addAll(myPatches);
final ApplyPatchStatus patchStatus = nonWriteActionPreCheck();
@@ -179,7 +164,7 @@ public class PatchApplier<BinaryType extends FilePatch> {
if(myShowNotification || !ApplyPatchStatus.SUCCESS.equals(myStatus)) {
showApplyStatus(myProject, myStatus);
}
refreshFiles(trigger.getAffected(), context);
refreshFiles(trigger.getAffected());
}
@CalledInAwt
@@ -240,9 +225,9 @@ public class PatchApplier<BinaryType extends FilePatch> {
return new ApplyPatchTask(showSuccessNotification, silentAddDelete);
}
@AsynchronousExecution
public void scheduleSelf(boolean showSuccessNotification, @NotNull final ContinuationContext context, boolean silentAddDelete) {
context.next(createApplyPart(showSuccessNotification, silentAddDelete));
@CalledInAwt
public void execute(boolean showSuccessNotification, boolean silentAddDelete) {
createApplyPart(showSuccessNotification, silentAddDelete).run();
}
@CalledInAwt
@@ -289,7 +274,7 @@ public class PatchApplier<BinaryType extends FilePatch> {
}
directlyAffected.addAll(trigger.getAffected());
final Consumer<Collection<FilePath>> mover = localChangeList == null ? null : createMover(project, localChangeList);
refreshPassedFilesAndMoveToChangelist(project, null, directlyAffected, indirectlyAffected, mover);
refreshPassedFilesAndMoveToChangelist(project, directlyAffected, indirectlyAffected, mover);
showApplyStatus(project, result);
return result;
}
@@ -347,12 +332,12 @@ public class PatchApplier<BinaryType extends FilePatch> {
}
@CalledInAwt
protected void refreshFiles(final Collection<FilePath> additionalDirectly, @Nullable final ContinuationContext context) {
protected void refreshFiles(final Collection<FilePath> additionalDirectly) {
final List<FilePath> directlyAffected = myVerifier.getDirectlyAffected();
final List<VirtualFile> indirectlyAffected = myVerifier.getAllAffected();
directlyAffected.addAll(additionalDirectly);
refreshPassedFilesAndMoveToChangelist(myProject, context, directlyAffected, indirectlyAffected, myToTargetListsMover);
refreshPassedFilesAndMoveToChangelist(myProject, directlyAffected, indirectlyAffected, myToTargetListsMover);
}
public List<FilePath> getDirectlyAffected() {
@@ -365,14 +350,9 @@ public class PatchApplier<BinaryType extends FilePatch> {
@CalledInAwt
public static void refreshPassedFilesAndMoveToChangelist(@NotNull final Project project,
final ContinuationContext context,
final Collection<FilePath> directlyAffected,
final Collection<VirtualFile> indirectlyAffected,
final Consumer<Collection<FilePath>> targetChangelistMover) {
if (context != null) {
context.suspend();
}
final LocalFileSystem lfs = LocalFileSystem.getInstance();
for (FilePath filePath : directlyAffected) {
lfs.refreshAndFindFileByIoFile(filePath.getIOFile());
@@ -386,11 +366,8 @@ public class PatchApplier<BinaryType extends FilePatch> {
@Override
public void run() {
targetChangelistMover.consume(directlyAffected);
if (context != null) {
context.ping();
}
}
}, InvokeAfterUpdateMode.BACKGROUND_CANCELLABLE,
}, InvokeAfterUpdateMode.SYNCHRONOUS_CANCELLABLE,
VcsBundle.message("change.lists.manager.move.changes.to.list"),
new Consumer<VcsDirtyScopeManager>() {
@Override
@@ -400,9 +377,6 @@ public class PatchApplier<BinaryType extends FilePatch> {
}, null);
} else {
markDirty(VcsDirtyScopeManager.getInstance(project), directlyAffected, indirectlyAffected);
if (context != null) {
context.ping();
}
}
}
@@ -33,6 +33,7 @@ import com.intellij.util.Consumer;
import com.intellij.util.containers.Convertor;
import com.intellij.util.containers.HashSet;
import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.CalledInAwt;
import java.util.Collection;
import java.util.LinkedList;
@@ -52,6 +53,7 @@ public class ApplyPatchDefaultExecutor implements ApplyPatchExecutor<AbstractFil
return null;
}
@CalledInAwt
@Override
public void apply(MultiMap<VirtualFile, AbstractFilePatchInProgress> patchGroups,
LocalChangeList localList,
@@ -55,6 +55,7 @@ import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.Convertor;
import com.intellij.util.containers.MultiMap;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.CalledInAwt;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -287,6 +288,7 @@ public class ApplyPatchDifferentiatedDialog extends DialogWrapper {
return actions.toArray(new Action[actions.size()]);
}
@CalledInAwt
private void runExecutor(ApplyPatchExecutor executor) {
final Collection<AbstractFilePatchInProgress> included = getIncluded();
if (included.isEmpty()) return;
@@ -25,6 +25,7 @@ package com.intellij.openapi.vcs.changes.shelf;
import com.intellij.ide.impl.ProjectUtil;
import com.intellij.lifecycle.PeriodicalTasksCloser;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.application.impl.LaterInvocator;
import com.intellij.openapi.components.AbstractProjectComponent;
@@ -33,7 +34,6 @@ import com.intellij.openapi.diff.impl.patch.*;
import com.intellij.openapi.diff.impl.patch.apply.ApplyFilePatchBase;
import com.intellij.openapi.diff.impl.patch.formove.CustomBinaryPatchApplier;
import com.intellij.openapi.diff.impl.patch.formove.PatchApplier;
import com.intellij.openapi.progress.AsynchronousExecution;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
@@ -52,13 +52,13 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Consumer;
import com.intellij.util.PathUtil;
import com.intellij.util.SmartList;
import com.intellij.util.continuation.*;
import com.intellij.util.messages.MessageBus;
import com.intellij.util.messages.Topic;
import com.intellij.util.text.CharArrayCharSequence;
import com.intellij.util.ui.UIUtil;
import com.intellij.vcsUtil.FilesProgress;
import org.jdom.Element;
import org.jetbrains.annotations.CalledInAny;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -355,60 +355,55 @@ public class ShelveChangesManager extends AbstractProjectComponent implements JD
}
}
@AsynchronousExecution
@CalledInAny
public void unshelveChangeList(final ShelvedChangeList changeList,
@Nullable final List<ShelvedChange> changes,
@Nullable final List<ShelvedBinaryFile> binaryFiles,
@Nullable final LocalChangeList targetChangeList,
boolean showSuccessNotification) {
final Continuation continuation = Continuation.createForCurrentProgress(myProject, true);
final GatheringContinuationContext initContext = new GatheringContinuationContext();
scheduleUnshelveChangeList(changeList, changes, binaryFiles, targetChangeList, showSuccessNotification, initContext, false,
false, null, null);
continuation.run(initContext.getList());
unshelveChangeList(changeList, changes, binaryFiles, targetChangeList, showSuccessNotification, false, false, null, null);
}
@AsynchronousExecution
public void scheduleUnshelveChangeList(final ShelvedChangeList changeList,
@Nullable final List<ShelvedChange> changes,
@Nullable final List<ShelvedBinaryFile> binaryFiles,
@Nullable final LocalChangeList targetChangeList,
final boolean showSuccessNotification,
final ContinuationContext context,
final boolean systemOperation,
final boolean reverse,
final String leftConflictTitle,
final String rightConflictTitle) {
context.next(new TaskDescriptor("", Where.AWT) {
@CalledInAny
public void unshelveChangeList(final ShelvedChangeList changeList,
@Nullable final List<ShelvedChange> changes,
@Nullable final List<ShelvedBinaryFile> binaryFiles,
@Nullable final LocalChangeList targetChangeList,
final boolean showSuccessNotification,
final boolean systemOperation,
final boolean reverse,
final String leftConflictTitle,
final String rightConflictTitle) {
final List<FilePatch> remainingPatches = new ArrayList<FilePatch>();
final CommitContext commitContext = new CommitContext();
final List<TextFilePatch> textFilePatches;
try {
textFilePatches = loadTextPatches(myProject, changeList, changes, remainingPatches, commitContext);
}
catch (IOException e) {
LOG.info(e);
PatchApplier.showError(myProject, "Cannot load patch(es): " + e.getMessage(), true);
return;
}
catch (PatchSyntaxException e) {
PatchApplier.showError(myProject, "Cannot load patch(es): " + e.getMessage(), true);
LOG.info(e);
return;
}
final List<FilePatch> patches = new ArrayList<FilePatch>(textFilePatches);
final List<ShelvedBinaryFile> remainingBinaries = new ArrayList<ShelvedBinaryFile>();
final List<ShelvedBinaryFile> binaryFilesToUnshelve = getBinaryFilesToUnshelve(changeList, binaryFiles, remainingBinaries);
for (final ShelvedBinaryFile shelvedBinaryFile : binaryFilesToUnshelve) {
patches.add(new ShelvedBinaryFilePatch(shelvedBinaryFile));
}
ApplicationManager.getApplication().invokeAndWait(new Runnable() {
@Override
public void run(ContinuationContext contextInner) {
final List<FilePatch> remainingPatches = new ArrayList<FilePatch>();
final CommitContext commitContext = new CommitContext();
final List<TextFilePatch> textFilePatches;
try {
textFilePatches = loadTextPatches(myProject, changeList, changes, remainingPatches, commitContext);
}
catch (IOException e) {
LOG.info(e);
PatchApplier.showError(myProject, "Cannot load patch(es): " + e.getMessage(), true);
return;
}
catch (PatchSyntaxException e) {
PatchApplier.showError(myProject, "Cannot load patch(es): " + e.getMessage(), true);
LOG.info(e);
return;
}
final List<FilePatch> patches = new ArrayList<FilePatch>(textFilePatches);
final List<ShelvedBinaryFile> remainingBinaries = new ArrayList<ShelvedBinaryFile>();
final List<ShelvedBinaryFile> binaryFilesToUnshelve = getBinaryFilesToUnshelve(changeList, binaryFiles, remainingBinaries);
for (final ShelvedBinaryFile shelvedBinaryFile : binaryFilesToUnshelve) {
patches.add(new ShelvedBinaryFilePatch(shelvedBinaryFile));
}
public void run() {
final BinaryPatchApplier binaryPatchApplier = new BinaryPatchApplier();
final PatchApplier<ShelvedBinaryFilePatch> patchApplier =
new PatchApplier<ShelvedBinaryFilePatch>(myProject, myProject.getBaseDir(),
@@ -416,24 +411,18 @@ public class ShelveChangesManager extends AbstractProjectComponent implements JD
rightConflictTitle);
patchApplier.setIsSystemOperation(systemOperation);
// after patch applier part
contextInner.next(new TaskDescriptor("", Where.AWT) {
@Override
public void run(ContinuationContext context) {
remainingPatches.addAll(patchApplier.getRemainingPatches());
remainingPatches.addAll(patchApplier.getRemainingPatches());
if (remainingPatches.isEmpty() && remainingBinaries.isEmpty()) {
recycleChangeList(changeList);
}
else {
saveRemainingPatches(changeList, remainingPatches, remainingBinaries, commitContext);
}
}
});
if (remainingPatches.isEmpty() && remainingBinaries.isEmpty()) {
recycleChangeList(changeList);
}
else {
saveRemainingPatches(changeList, remainingPatches, remainingBinaries, commitContext);
}
patchApplier.scheduleSelf(showSuccessNotification, contextInner, systemOperation);
patchApplier.execute(showSuccessNotification, systemOperation);
}
});
}, ModalityState.defaultModalityState());
}
private static List<TextFilePatch> loadTextPatches(final Project project,
@@ -24,7 +24,6 @@ import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.VcsNotifier;
import com.intellij.openapi.vcs.changes.ChangeListManagerEx;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.continuation.ContinuationContext;
import git4idea.GitPlatformFacade;
import git4idea.commands.Git;
import git4idea.config.GitVcsSettings;
@@ -108,8 +107,8 @@ public abstract class GitChangesSaver {
* Loads local changes from stash or shelf, and sorts the changes back to the change lists they were before update.
* @param context
*/
public void restoreLocalChanges(ContinuationContext context) {
load(context);
public void restoreLocalChanges() {
load();
}
public void notifyLocalChangesAreNotRestored() {
@@ -138,9 +137,8 @@ public abstract class GitChangesSaver {
/**
* Loads the changes - specific for chosen save strategy.
* @param exceptionConsumer
*/
protected abstract void load(ContinuationContext exceptionConsumer);
public abstract void load();
/**
* @return true if there were local changes to save.
@@ -25,7 +25,6 @@ import com.intellij.openapi.vcs.changes.shelf.ShelvedChangeList;
import com.intellij.openapi.vcs.changes.shelf.ShelvedChangesViewManager;
import com.intellij.openapi.vcs.impl.LocalChangesUnderRoots;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.continuation.ContinuationContext;
import git4idea.GitPlatformFacade;
import git4idea.commands.Git;
import git4idea.i18n.GitBundle;
@@ -85,13 +84,14 @@ public class GitShelveChangesSaver extends GitChangesSaver {
myProgressIndicator.setText(oldProgressTitle);
}
protected void load(ContinuationContext context) {
@Override
public void load() {
if (myShelvedLists != null) {
LOG.info("load ");
String oldProgressTitle = myProgressIndicator.getText();
myProgressIndicator.setText(GitBundle.getString("update.unshelving.changes"));
for (ShelvedChangeList list : myShelvedLists.values()) {
GitShelveUtils.doSystemUnshelve(myProject, list, myShelveManager, context,
GitShelveUtils.doSystemUnshelve(myProject, list, myShelveManager,
getConflictLeftPanelTitle(), getConflictRightPanelTitle());
}
myProgressIndicator.setText(oldProgressTitle);
@@ -20,7 +20,6 @@ import com.intellij.openapi.command.undo.DocumentReference;
import com.intellij.openapi.command.undo.DocumentReferenceManager;
import com.intellij.openapi.command.undo.UndoManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.AsynchronousExecution;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.Change;
@@ -33,9 +32,6 @@ import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Processor;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.continuation.ContinuationContext;
import com.intellij.util.continuation.TaskDescriptor;
import com.intellij.util.continuation.Where;
import org.jetbrains.annotations.CalledInAwt;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -47,53 +43,29 @@ import java.util.Collection;
import java.util.HashSet;
import java.util.List;
/**
* @author Kirill Likhodedov
*/
public class GitShelveUtils {
private static final Logger LOG = Logger.getInstance(GitShelveUtils.class.getName());
/**
* Perform system level unshelve operation
*
* @param project the project
* @param shelvedChangeList the shelved change list
* @param shelveManager the shelve manager
*/
@AsynchronousExecution
public static void doSystemUnshelve(final Project project, final ShelvedChangeList shelvedChangeList,
public static void doSystemUnshelve(final Project project,
final ShelvedChangeList shelvedChangeList,
final ShelveChangesManager shelveManager,
final @NotNull ContinuationContext context,
@Nullable final String leftConflictTitle, @Nullable final String rightConflictTitle) {
@Nullable final String leftConflictTitle,
@Nullable final String rightConflictTitle) {
VirtualFile baseDir = project.getBaseDir();
assert baseDir != null;
final String projectPath = baseDir.getPath() + "/";
final List<ShelvedChange> changes = shelvedChangeList.getChanges(project);
context.next(new TaskDescriptor("Refreshing files before unshelve", Where.POOLED) {
@Override
public void run(ContinuationContext context) {
LOG.info("doSystemUnshelve ");
// The changes are temporary copied to the first local change list, the next operation will restore them back
// Refresh files that might be affected by unshelve
refreshFilesBeforeUnshelve(project, shelvedChangeList, projectPath);
LOG.info("doSystemUnshelve files refreshed. unshelving in AWT thread.");
}
}, new TaskDescriptor("", Where.AWT) {
@Override
public void run(ContinuationContext context) {
LOG.info("Unshelving in UI thread. shelvedChangeList: " + shelvedChangeList);
// we pass null as target change list for Patch Applier to do NOTHING with change lists
shelveManager.scheduleUnshelveChangeList(shelvedChangeList, changes,
shelvedChangeList.getBinaryFiles(), null, false, context, true,
true, leftConflictTitle, rightConflictTitle);
}
}, new TaskDescriptor("", Where.AWT) {
@Override
public void run(ContinuationContext context) {
markUnshelvedFilesNonUndoable(project, changes);
}
});
LOG.info("refreshing files ");
// The changes are temporary copied to the first local change list, the next operation will restore them back
// Refresh files that might be affected by unshelve
refreshFilesBeforeUnshelve(project, shelvedChangeList, projectPath);
LOG.info("Unshelving shelvedChangeList: " + shelvedChangeList);
// we pass null as target change list for Patch Applier to do NOTHING with change lists
List<ShelvedChange> changes = shelvedChangeList.getChanges(project);
shelveManager.unshelveChangeList(shelvedChangeList, changes, shelvedChangeList.getBinaryFiles(), null, false, true,
true, leftConflictTitle, rightConflictTitle);
markUnshelvedFilesNonUndoable(project, changes);
}
@CalledInAwt
@@ -116,7 +88,7 @@ public class GitShelveUtils {
}
}
public static void refreshFilesBeforeUnshelve(final Project project, ShelvedChangeList shelvedChangeList, String projectPath) {
private static void refreshFilesBeforeUnshelve(final Project project, ShelvedChangeList shelvedChangeList, String projectPath) {
HashSet<File> filesToRefresh = new HashSet<File>();
for (ShelvedChange c : shelvedChangeList.getChanges(project)) {
if (c.getBeforePath() != null) {
@@ -28,7 +28,6 @@ import com.intellij.openapi.vcs.impl.LocalChangesUnderRoots;
import com.intellij.openapi.vcs.merge.MergeDialogCustomizer;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.continuation.ContinuationContext;
import git4idea.GitPlatformFacade;
import git4idea.commands.Git;
import git4idea.commands.GitCommandResult;
@@ -69,16 +68,7 @@ public class GitStashChangesSaver extends GitChangesSaver {
}
@Override
protected void load(@NotNull ContinuationContext context) {
try {
load();
}
catch (VcsException e) {
context.handleException(e, false);
}
}
public void load() throws VcsException {
public void load() {
for (VirtualFile root : myStashedRoots) {
loadRoot(root);
}
@@ -129,7 +119,7 @@ public class GitStashChangesSaver extends GitChangesSaver {
* Returns true if the root was loaded with conflict.
* False is returned in all other cases: in the case of success and in case of some other error.
*/
private boolean loadRoot(final VirtualFile root) throws VcsException {
private boolean loadRoot(final VirtualFile root) {
LOG.info("loadRoot " + root);
myProgressIndicator.setText(GitHandlerUtil.formatOperationName("Unstashing changes to", root));
@@ -30,14 +30,9 @@ import com.intellij.openapi.vcs.changes.ChangeListManager;
import com.intellij.openapi.vcs.impl.LocalChangesUnderRoots;
import com.intellij.openapi.vcs.update.UpdatedFiles;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Consumer;
import com.intellij.util.Function;
import com.intellij.util.ObjectUtils;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.continuation.ContinuationContext;
import com.intellij.util.continuation.ContinuationFinalTasksInserter;
import com.intellij.util.continuation.TaskDescriptor;
import com.intellij.util.continuation.Where;
import com.intellij.util.text.DateFormatUtil;
import git4idea.GitLocalBranch;
import git4idea.GitPlatformFacade;
@@ -54,12 +49,12 @@ import git4idea.rebase.GitRebaser;
import git4idea.repo.GitBranchTrackInfo;
import git4idea.repo.GitRepository;
import git4idea.stash.GitChangesSaver;
import git4idea.util.GitFreezingProcess;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import static git4idea.util.GitUIUtil.*;
@@ -74,6 +69,7 @@ public class GitUpdateProcess {
@NotNull private final Project myProject;
@NotNull private final Git myGit;
@NotNull private final GitPlatformFacade myPlatformFacade;
@NotNull private final Collection<GitRepository> myRepositories;
private final boolean myCheckRebaseOverMergeProblem;
private final UpdatedFiles myUpdatedFiles;
@@ -83,7 +79,6 @@ public class GitUpdateProcess {
private final Map<VirtualFile, GitBranchPair> myTrackedBranches = new HashMap<VirtualFile, GitBranchPair>();
private GitUpdateResult myResult;
private final Collection<VirtualFile> myRootsToSave;
public GitUpdateProcess(@NotNull Project project,
@NotNull GitPlatformFacade platformFacade,
@@ -92,6 +87,7 @@ public class GitUpdateProcess {
@NotNull UpdatedFiles updatedFiles,
boolean checkRebaseOverMergeProblem) {
myProject = project;
myPlatformFacade = platformFacade;
myRepositories = repositories;
myCheckRebaseOverMergeProblem = checkRebaseOverMergeProblem;
myGit = ServiceManager.getService(Git.class);
@@ -136,26 +132,23 @@ public class GitUpdateProcess {
if (!fetchAndNotify()) {
return GitUpdateResult.NOT_READY;
}
GitComplexProcess.Operation updateOperation = new GitComplexProcess.Operation() {
@Override public void run(ContinuationContext continuationContext) {
new GitFreezingProcess(myProject, myPlatformFacade, "update", new Runnable() {
public void run() {
AccessToken token = DvcsUtil.workingTreeChangeStarted(myProject);
try {
myResult = updateImpl(updateMethod, continuationContext);
myResult = updateImpl(updateMethod);
}
finally {
DvcsUtil.workingTreeChangeFinished(myProject, token);
}
}
};
GitComplexProcess.execute(myProject, "update", updateOperation);
}).execute();
myProgressIndicator.setText(oldText);
return myResult;
}
@NotNull
private GitUpdateResult updateImpl(@NotNull UpdateMethod updateMethod, ContinuationContext context) {
private GitUpdateResult updateImpl(@NotNull UpdateMethod updateMethod) {
Map<VirtualFile, GitUpdater> updaters;
try {
updaters = defineUpdaters(updateMethod);
@@ -193,6 +186,7 @@ public class GitUpdateProcess {
}
// save local changes if needed (update via merge may perform without saving).
Collection<VirtualFile> myRootsToSave = ContainerUtil.newArrayList();
LOG.info("updateImpl: identifying if save is needed...");
for (Map.Entry<VirtualFile, GitUpdater> entry : updaters.entrySet()) {
VirtualFile root = entry.getKey();
@@ -244,7 +238,7 @@ public class GitUpdateProcess {
}
else {
LOG.info("updateImpl: restoring local changes...");
restoreLocalChanges(context);
restoreLocalChanges();
}
}
return compoundResult;
@@ -312,28 +306,9 @@ public class GitUpdateProcess {
return compoundResult.join(result);
}
private void restoreLocalChanges(ContinuationContext context) {
context.addExceptionHandler(VcsException.class, new Consumer<VcsException>() {
@Override
public void consume(VcsException e) {
LOG.info("Couldn't restore local changes after update", e);
notifyImportantError(myProject, "Couldn't restore local changes after update",
"Restoring changes saved before update failed with an error.<br/>" + e.getLocalizedMessage());
}
});
// try restore changes under all circumstances
final ContinuationFinalTasksInserter finalTasksInserter = new ContinuationFinalTasksInserter(context);
finalTasksInserter.allNextAreFinal();
// !!!! this task is put NEXT, i.e. if unshelve/unstash will be done synchronously or scheduled on context,
// it is unimportant -> files will be refreshed after
context.next(new TaskDescriptor("Refresh local files", Where.POOLED) {
@Override
public void run(ContinuationContext context) {
mySaver.refresh();
}
});
mySaver.restoreLocalChanges(context);
finalTasksInserter.removeFinalPropertyAdder();
private void restoreLocalChanges() {
mySaver.restoreLocalChanges();
mySaver.refresh();
}
// fetch all roots. If an error happens, return false and notify about errors.
@@ -167,15 +167,7 @@ public class GitPreservingProcess {
public void load() {
if (myLoaded.compareAndSet(false, true)) {
try {
mySaver.load();
}
catch (VcsException e) {
LOG.info("Couldn't load local changes", e);
VcsNotifier.getInstance(myProject).notifyError("Couldn't restore uncommitted changes",
String.format("Tried to unstash uncommitted changes, but failed with error.<br/>%s",
join(e.getMessages())));
}
mySaver.load();
}
else {
LOG.warn("The changes were already loaded", new Throwable());
@@ -256,7 +256,7 @@ public class MergeFromTheirsResolver {
final PatchApplier<BinaryFilePatch> patchApplier =
new PatchApplier<BinaryFilePatch>(myVcs.getProject(), myBaseDir, patches, localList, null, null);
patchApplier.scheduleSelf(false, myInner, true); // 3
patchApplier.execute(false, true); // 3
boolean thereAreCreations = false;
for (FilePatch patch : patches) {
if (patch.isNewFile() || ! Comparing.equal(patch.getAfterName(), patch.getBeforeName())) {