VCS: refresh of local changes is buffered while updating; SVN: dirty scope is merged in case of single dirty files + no "java.io.File list" to fetch files under dirty dir; svnkit: build 1.2.x next-after-5664

This commit is contained in:
Irina Chernushina
2009-04-08 16:02:43 +04:00
parent a85a62bb5c
commit d7ecb2975d
3 changed files with 164 additions and 25 deletions
@@ -3,27 +3,43 @@ package com.intellij.openapi.vcs;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.Convertor;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class ObjectsConvertor {
private static final Convertor<FilePath, VirtualFile> FILEPATH_TO_VIRTUAL = new Convertor<FilePath, VirtualFile>() {
public VirtualFile convert(FilePath fp) {
return fp.getVirtualFile();
}
};
private static final Convertor<VirtualFile, FilePath> VIRTUAL_FILEPATH = new Convertor<VirtualFile, FilePath>() {
public FilePath convert(VirtualFile vf) {
return new FilePathImpl(vf);
}
};
private static final Convertor<FilePath, File> FILEPATH_FILE = new Convertor<FilePath, File>() {
public File convert(FilePath fp) {
return fp.getIOFile();
}
};
public static List<VirtualFile> fp2vf(final List<FilePath> in) {
return convert(in, new Convertor<FilePath, VirtualFile>() {
public VirtualFile convert(final FilePath fp) {
return fp.getVirtualFile();
}
});
return convert(in, FILEPATH_TO_VIRTUAL);
}
public static List<FilePath> vf2fp(final List<VirtualFile> in) {
return convert(in, new Convertor<VirtualFile, FilePath>() {
public FilePath convert(final VirtualFile vf) {
return new FilePathImpl(vf);
}
});
return convert(in, VIRTUAL_FILEPATH);
}
public static <T,S> List<S> convert(final List<T> in, final Convertor<T,S> convertor) {
public static List<File> fp2jiof(final Collection<FilePath> in) {
return convert(in, FILEPATH_FILE);
}
public static <T,S> List<S> convert(final Collection<T> in, final Convertor<T,S> convertor) {
final List<S> out = new ArrayList<S>();
for (T t : in) {
out.add(convertor.convert(t));
@@ -63,16 +63,32 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr
}
}
public void suspendMe() {
myLife.suspendMe();
}
public void reanimate() {
final Ref<Boolean> wasNotEmptyRef = new Ref<Boolean>();
myLife.releaseMe(new Runnable() {
public void run() {
wasNotEmptyRef.set(! myDirtBuilder.isEmpty());
}
});
if (Boolean.TRUE.equals(wasNotEmptyRef.get())) {
myChangeListManager.scheduleUpdate();
}
}
public void markEverythingDirty() {
if (myProject.isDisposed()) return;
final boolean done = myLife.doIfAlive(new Runnable() {
final LifeDrop lifeDrop = myLife.doIfAlive(new Runnable() {
public void run() {
myDirtBuilder.everythingDirty();
}
});
if (done) {
if (lifeDrop.isDone() && (! lifeDrop.isSuspened())) {
myChangeListManager.scheduleUpdate();
}
}
@@ -112,17 +128,20 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr
}
private boolean takeDirt(final Consumer<DirtBuilder> filler) {
final boolean done = myLife.doIfAlive(new Runnable() {
final Ref<Boolean> wasNotEmptyRef = new Ref<Boolean>();
final Runnable runnable = new Runnable() {
public void run() {
filler.consume(myDirtBuilder);
wasNotEmptyRef.set(!myDirtBuilder.isEmpty());
}
});
};
final LifeDrop lifeDrop = myLife.doIfAlive(runnable);
if (done && (! myDirtBuilder.isEmpty())) {
if (lifeDrop.isDone() && (! lifeDrop.isSuspened()) && (Boolean.TRUE.equals(wasNotEmptyRef.get()))) {
myChangeListManager.scheduleUpdate();
}
// no sence in checking correct here any more: vcs is searched for asynchronously
return (! done);
return (! lifeDrop.isDone());
}
public boolean filesDirty(@Nullable final Collection<VirtualFile> filesDirty, @Nullable final Collection<VirtualFile> dirsRecursivelyDirty) {
@@ -182,14 +201,14 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr
public VcsInvalidated retrieveScopes() {
final Ref<DirtBuilder> dirtCopyRef = new Ref<DirtBuilder>();
final boolean done = myLife.doIfAlive(new Runnable() {
final LifeDrop lifeDrop = myLife.doIfAlive(new Runnable() {
public void run() {
dirtCopyRef.set(new DirtBuilder(myDirtBuilder));
myDirtBuilder.reset();
}
});
if (done && (! dirtCopyRef.isNull())) {
if (lifeDrop.isDone() && (! dirtCopyRef.isNull())) {
return ApplicationManager.getApplication().runReadAction(new Computable<VcsInvalidated>() {
public VcsInvalidated compute() {
final Scopes scopes = new Scopes(myProject, myGuess);
@@ -201,6 +220,23 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr
return null;
}
private String toStringScopes(final VcsInvalidated vcsInvalidated) {
final StringBuilder sb = new StringBuilder();
sb.append("is everything dirty: ").append(vcsInvalidated.isEverythingDirty()).append(";\n");
for (VcsDirtyScope scope : vcsInvalidated.getScopes()) {
sb.append("|\nFiles: ");
for (FilePath path : scope.getDirtyFiles()) {
sb.append(path).append('\n');
}
sb.append("\nDirs: ");
for (FilePath filePath : scope.getRecursivelyDirtyDirectories()) {
sb.append(filePath).append('\n');
}
}
sb.append("-------------");
return sb.toString();
}
private class MyVfsListener extends VirtualFileAdapter {
@Override
public void contentsChanged(VirtualFileEvent event) {
@@ -267,9 +303,28 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr
}
}
private static class LifeDrop {
private final boolean myDone;
private final boolean mySuspened;
private LifeDrop(boolean done, boolean suspened) {
myDone = done;
mySuspened = suspened;
}
public boolean isDone() {
return myDone;
}
public boolean isSuspened() {
return mySuspened;
}
}
private static class SynchronizedLife {
private LifeStages myStage;
private final Object myLock;
private boolean mySuspended;
private SynchronizedLife() {
myStage = LifeStages.NOT_BORN;
@@ -288,15 +343,44 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr
}
}
public void suspendMe() {
synchronized (myLock) {
if (LifeStages.ALIVE.equals(myStage)) {
mySuspended = true;
}
}
}
public void releaseMe(final Runnable runnable) {
synchronized (myLock) {
if (LifeStages.ALIVE.equals(myStage)) {
mySuspended = false;
runnable.run();
}
}
}
public LifeDrop doIfAliveAndNotSuspended(final Runnable runnable) {
synchronized (myLock) {
synchronized (myLock) {
if (LifeStages.ALIVE.equals(myStage) && (! mySuspended)) {
runnable.run();
return new LifeDrop(true, mySuspended);
}
return new LifeDrop(false, mySuspended);
}
}
}
// allow work under inner lock: inner class, not wide scope
public boolean doIfAlive(final Runnable runnable) {
public LifeDrop doIfAlive(final Runnable runnable) {
synchronized (myLock) {
if (LifeStages.ALIVE.equals(myStage)) {
runnable.run();
return true;
return new LifeDrop(true, mySuspended);
}
return new LifeDrop(false, mySuspended);
}
return false;
}
private static enum LifeStages {
@@ -50,6 +50,7 @@ import com.intellij.openapi.vcs.*;
import com.intellij.openapi.vcs.actions.AbstractVcsAction;
import com.intellij.openapi.vcs.actions.VcsContext;
import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager;
import com.intellij.openapi.vcs.changes.VcsDirtyScopeManagerImpl;
import com.intellij.openapi.vcs.changes.committed.CommittedChangesAdapter;
import com.intellij.openapi.vcs.changes.committed.CommittedChangesCache;
import com.intellij.openapi.vcs.changes.ui.ChangesViewContentManager;
@@ -305,11 +306,13 @@ public abstract class AbstractCommonUpdateAction extends AbstractVcsAction {
// vcs name, context object
private final Map<String, SequentialUpdatesContext> myContextInfo;
private VcsDirtyScopeManager myDirtyScopeManager;
public Updater(final Project project, final FilePath[] roots, final Map<AbstractVcs, Collection<FilePath>> vcsToVirtualFiles) {
super(project, getTemplatePresentation().getText(), true, VcsConfiguration.getInstance(project).getUpdateOption());
myProject = project;
myProjectLevelVcsManager = ProjectLevelVcsManagerEx.getInstanceEx(project);
myDirtyScopeManager = VcsDirtyScopeManager.getInstance(myProject);
myRoots = roots;
myVcsToVirtualFiles = vcsToVirtualFiles;
@@ -329,7 +332,36 @@ public abstract class AbstractCommonUpdateAction extends AbstractVcsAction {
++ myUpdateNumber;
}
private void suspendIfNeeded() {
if (! myActionInfo.canChangeFileStatus()) {
// i.e. for update but not for integrate or status
((VcsDirtyScopeManagerImpl) myDirtyScopeManager).suspendMe();
}
}
private void releaseIfNeeded() {
if (! myActionInfo.canChangeFileStatus()) {
// i.e. for update but not for integrate or status
((VcsDirtyScopeManagerImpl) myDirtyScopeManager).reanimate();
}
}
public void run(@NotNull final ProgressIndicator indicator) {
suspendIfNeeded();
try {
runImpl(indicator);
} catch (Throwable t) {
releaseIfNeeded();
if (t instanceof Error) {
throw ((Error) t);
} else if (t instanceof RuntimeException) {
throw ((RuntimeException) t);
}
throw new RuntimeException(t);
}
}
private void runImpl(@NotNull final ProgressIndicator indicator) {
ProjectManagerEx.getInstanceEx().blockReloadingProjectOnExternalChanges();
myProjectLevelVcsManager.startBackgroundVcsOperation();
ProgressIndicator progressIndicator = ProgressManager.getInstance().getProgressIndicator();
@@ -405,6 +437,14 @@ public abstract class AbstractCommonUpdateAction extends AbstractVcsAction {
}
public void onSuccess() {
try {
onSuccessImpl();
} finally {
releaseIfNeeded();
}
}
private void onSuccessImpl() {
if (myProject.isDisposed()) {
ProjectManagerEx.getInstanceEx().unblockReloadingProjectOnExternalChanges();
return;
@@ -423,7 +463,6 @@ public abstract class AbstractCommonUpdateAction extends AbstractVcsAction {
}
if (myActionInfo.canChangeFileStatus()) {
final VcsDirtyScopeManager myManager = VcsDirtyScopeManager.getInstance(myProject);
final List<VirtualFile> files = new ArrayList<VirtualFile>();
UpdateFilesHelper.iterateFileGroupFiles(myUpdatedFiles, new UpdateFilesHelper.Callback() {
public void onFile(final String filePath, final String groupId) {
@@ -434,7 +473,7 @@ public abstract class AbstractCommonUpdateAction extends AbstractVcsAction {
}
}
});
myManager.filesDirty(files, null);
myDirtyScopeManager.filesDirty(files, null);
}
final boolean updateSuccess = (! someSessionWasCancelled) && (myVcsExceptions.isEmpty());