mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-57639 Stuck on Open Project, Cancel Button does not work (add file watch requests in pooled thread, not synchronously during initialization)
This commit is contained in:
+64
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2000-2010 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.openapi.vcs.impl.projectlevelman;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vcs.VcsDirectoryMapping;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author irengrig
|
||||
*/
|
||||
public class FileWatchRequestModifier implements Runnable {
|
||||
private final Project myProject;
|
||||
private final NewMappings myNewMappings;
|
||||
private final Map<VcsDirectoryMapping, LocalFileSystem.WatchRequest> myDirectoryMappingWatches;
|
||||
private final LocalFileSystem myLfs;
|
||||
|
||||
public FileWatchRequestModifier(final Project project, final NewMappings newMappings, final LocalFileSystem localFileSystem) {
|
||||
myLfs = localFileSystem;
|
||||
myProject = project;
|
||||
myNewMappings = newMappings;
|
||||
myDirectoryMappingWatches = new HashMap<VcsDirectoryMapping, LocalFileSystem.WatchRequest>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if ((! myProject.isInitialized()) || myProject.isDisposed()) return;
|
||||
final List<VcsDirectoryMapping> copy = myNewMappings.getDirectoryMappings();
|
||||
|
||||
final List<VcsDirectoryMapping> added = new LinkedList<VcsDirectoryMapping>(copy);
|
||||
added.removeAll(myDirectoryMappingWatches.keySet());
|
||||
|
||||
final List<VcsDirectoryMapping> deleted = new LinkedList<VcsDirectoryMapping>(myDirectoryMappingWatches.keySet());
|
||||
deleted.removeAll(copy);
|
||||
|
||||
for (VcsDirectoryMapping mapping : added) {
|
||||
if (mapping.isDefaultMapping()) continue;
|
||||
final LocalFileSystem.WatchRequest watchRequest = myLfs.addRootToWatch(mapping.getDirectory(), true);
|
||||
myDirectoryMappingWatches.put(mapping, watchRequest);
|
||||
}
|
||||
for (VcsDirectoryMapping mapping : deleted) {
|
||||
if (mapping.isDefaultMapping()) continue;
|
||||
myLfs.removeWatchedRoot(myDirectoryMappingWatches.remove(mapping));
|
||||
}
|
||||
}
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2000-2010 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.openapi.vcs.impl.projectlevelman;
|
||||
|
||||
import com.intellij.openapi.application.Application;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vcs.RequestsMerger;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.util.Consumer;
|
||||
|
||||
/**
|
||||
* @author irengrig
|
||||
*/
|
||||
public class FileWatchRequestsManager {
|
||||
private final RequestsMerger myMerger;
|
||||
private final Project myProject;
|
||||
|
||||
public FileWatchRequestsManager(final Project project, final NewMappings newMappings, final LocalFileSystem localFileSystem) {
|
||||
myProject = project;
|
||||
myMerger = new RequestsMerger(new FileWatchRequestModifier(project, newMappings, localFileSystem), new Consumer<Runnable>() {
|
||||
@Override
|
||||
public void consume(Runnable runnable) {
|
||||
if ((! myProject.isInitialized()) || myProject.isDisposed()) return;
|
||||
final Application application = ApplicationManager.getApplication();
|
||||
if (application.isUnitTestMode()) {
|
||||
runnable.run();
|
||||
} else {
|
||||
application.executeOnPooledThread(runnable);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void ping() {
|
||||
myMerger.request();
|
||||
}
|
||||
}
|
||||
+22
-109
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.openapi.vcs.impl.projectlevelman;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.DumbAwareRunnable;
|
||||
import com.intellij.openapi.project.Project;
|
||||
@@ -46,8 +47,8 @@ public class NewMappings {
|
||||
private final Map<String, List<VcsDirectoryMapping>> myVcsToPaths;
|
||||
private AbstractVcs[] myActiveVcses;
|
||||
private VcsDirectoryMapping[] mySortedMappings;
|
||||
private final Map<VcsDirectoryMapping, LocalFileSystem.WatchRequest> myDirectoryMappingWatches;
|
||||
|
||||
private FileWatchRequestsManager myFileWatchRequestsManager;
|
||||
|
||||
private final DefaultVcsRootPolicy myDefaultVcsRootPolicy;
|
||||
private final EventDispatcher<VcsListener> myEventDispatcher;
|
||||
private final FileStatusManager myFileStatusManager;
|
||||
@@ -61,7 +62,7 @@ public class NewMappings {
|
||||
myFileStatusManager = fileStatusManager;
|
||||
myLock = new Object();
|
||||
myVcsToPaths = new HashMap<String, List<VcsDirectoryMapping>>();
|
||||
myDirectoryMappingWatches = new HashMap<VcsDirectoryMapping, LocalFileSystem.WatchRequest>();
|
||||
myFileWatchRequestsManager = new FileWatchRequestsManager(myProject, this, LocalFileSystem.getInstance());
|
||||
myDefaultVcsRootPolicy = DefaultVcsRootPolicy.getInstance(project);
|
||||
myActiveVcses = new AbstractVcs[0];
|
||||
myEventDispatcher = eventDispatcher;
|
||||
@@ -80,6 +81,12 @@ public class NewMappings {
|
||||
});
|
||||
}
|
||||
|
||||
// for tests
|
||||
public void setFileWatchRequestsManager(FileWatchRequestsManager fileWatchRequestsManager) {
|
||||
assert ApplicationManager.getApplication().isUnitTestMode();
|
||||
myFileWatchRequestsManager = fileWatchRequestsManager;
|
||||
}
|
||||
|
||||
public AbstractVcs[] getActiveVcses() {
|
||||
synchronized (myLock) {
|
||||
final AbstractVcs[] result = new AbstractVcs[myActiveVcses.length];
|
||||
@@ -111,7 +118,6 @@ public class NewMappings {
|
||||
}
|
||||
|
||||
}
|
||||
final LocalFileSystem.WatchRequest request = addWatchRequest(newMapping);
|
||||
|
||||
final Ref<Boolean> switched = new Ref<Boolean>(Boolean.FALSE);
|
||||
keepActiveVcs(new Runnable() {
|
||||
@@ -122,18 +128,10 @@ public class NewMappings {
|
||||
final List<VcsDirectoryMapping> newList = listForVcsFromMap(newMapping.getVcs());
|
||||
newList.add(newMapping);
|
||||
sortedMappingsByMap();
|
||||
|
||||
if (request != null) {
|
||||
myDirectoryMappingWatches.put(newMapping, request);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (switched.get().booleanValue() && (request != null)) {
|
||||
LocalFileSystem.getInstance().removeWatchedRoot(request);
|
||||
}
|
||||
|
||||
mappingsChanged();
|
||||
}
|
||||
|
||||
@@ -173,6 +171,7 @@ public class NewMappings {
|
||||
public void mappingsChanged() {
|
||||
myEventDispatcher.getMulticaster().directoryMappingChanged();
|
||||
myFileStatusManager.fileStatusesChanged();
|
||||
myFileWatchRequestsManager.ping();
|
||||
}
|
||||
|
||||
@Modification
|
||||
@@ -180,17 +179,16 @@ public class NewMappings {
|
||||
LOG.debug("setDirectoryMappings, size: " + items.size());
|
||||
MySetMappingsPreProcessor setMappingsPreProcessor = new MySetMappingsPreProcessor(items);
|
||||
setMappingsPreProcessor.invoke();
|
||||
final List<VcsDirectoryMapping> itemsCopy = setMappingsPreProcessor.getItemsCopy();
|
||||
final Map<VcsDirectoryMapping, LocalFileSystem.WatchRequest> requests = setMappingsPreProcessor.getRequests();
|
||||
|
||||
final Collection<LocalFileSystem.WatchRequest> toRemove = new ArrayList<LocalFileSystem.WatchRequest>();
|
||||
final List<VcsDirectoryMapping> itemsCopy;
|
||||
if (items.isEmpty()) {
|
||||
itemsCopy = Collections.singletonList(new VcsDirectoryMapping("", ""));
|
||||
} else {
|
||||
itemsCopy = items;
|
||||
}
|
||||
|
||||
keepActiveVcs(new Runnable() {
|
||||
public void run() {
|
||||
// a copy!
|
||||
toRemove.addAll(myDirectoryMappingWatches.values());
|
||||
myDirectoryMappingWatches.clear();
|
||||
|
||||
myVcsToPaths.clear();
|
||||
for (VcsDirectoryMapping mapping : itemsCopy) {
|
||||
listForVcsFromMap(mapping.getVcs()).add(mapping);
|
||||
@@ -199,11 +197,6 @@ public class NewMappings {
|
||||
}
|
||||
});
|
||||
|
||||
// do not remove what added and is active
|
||||
toRemove.removeAll(requests.values());
|
||||
// tracked by request object reference so OK to first add and then remove
|
||||
LocalFileSystem.getInstance().removeWatchedRoots(toRemove);
|
||||
|
||||
mappingsChanged();
|
||||
}
|
||||
|
||||
@@ -293,21 +286,14 @@ public class NewMappings {
|
||||
// if vcses were not mapped, there's nothing to clear
|
||||
if ((myActiveVcses == null) || (myActiveVcses.length == 0)) return;
|
||||
|
||||
final Collection<LocalFileSystem.WatchRequest> toRemove = new ArrayList<LocalFileSystem.WatchRequest>();
|
||||
keepActiveVcs(new Runnable() {
|
||||
public void run() {
|
||||
// a copy!
|
||||
toRemove.addAll(myDirectoryMappingWatches.values());
|
||||
myDirectoryMappingWatches.clear();
|
||||
|
||||
myVcsToPaths.clear();
|
||||
myActiveVcses = new AbstractVcs[0];
|
||||
mySortedMappings = new VcsDirectoryMapping[0];
|
||||
}
|
||||
});
|
||||
if (! toRemove.isEmpty()) {
|
||||
LocalFileSystem.getInstance().removeWatchedRoots(toRemove);
|
||||
}
|
||||
myFileWatchRequestsManager.ping();
|
||||
}
|
||||
|
||||
public List<VcsDirectoryMapping> getDirectoryMappings() {
|
||||
@@ -324,11 +310,10 @@ public class NewMappings {
|
||||
}
|
||||
|
||||
public void cleanupMappings() {
|
||||
final List<LocalFileSystem.WatchRequest> watchRequestList;
|
||||
synchronized (myLock) {
|
||||
watchRequestList = removeRedundantMappings();
|
||||
removeRedundantMappings();
|
||||
}
|
||||
LocalFileSystem.getInstance().removeWatchedRoots(watchRequestList);
|
||||
myFileWatchRequestsManager.ping();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -349,70 +334,23 @@ public class NewMappings {
|
||||
@Modification
|
||||
public void removeDirectoryMapping(final VcsDirectoryMapping mapping) {
|
||||
LOG.debug("remove mapping: " + mapping.getDirectory());
|
||||
final Ref<LocalFileSystem.WatchRequest> request = new Ref<LocalFileSystem.WatchRequest>();
|
||||
|
||||
keepActiveVcs(new Runnable() {
|
||||
public void run() {
|
||||
if (removeVcsFromMap(mapping, mapping.getVcs())) {
|
||||
sortedMappingsByMap();
|
||||
request.set(myDirectoryMappingWatches.remove(mapping));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (! request.isNull()) {
|
||||
LocalFileSystem.getInstance().removeWatchedRoot(request.get());
|
||||
}
|
||||
|
||||
mappingsChanged();
|
||||
}
|
||||
|
||||
private class MyMappingsFilter extends AbstractFilterChildren<VcsDirectoryMapping> {
|
||||
private final List<LocalFileSystem.WatchRequest> myRemovedRequests;
|
||||
|
||||
private MyMappingsFilter() {
|
||||
myRemovedRequests = new ArrayList<LocalFileSystem.WatchRequest>();
|
||||
}
|
||||
|
||||
protected void sortAscending(List<VcsDirectoryMapping> vcsDirectoryMappings) {
|
||||
// todo ordering is actually here
|
||||
Collections.sort(vcsDirectoryMappings, MyMappingsComparator.getInstance());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRemove(final VcsDirectoryMapping vcsDirectoryMapping) {
|
||||
final LocalFileSystem.WatchRequest request = myDirectoryMappingWatches.remove(vcsDirectoryMapping);
|
||||
if (request != null) {
|
||||
myRemovedRequests.add(request);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isAncestor(VcsDirectoryMapping parent, VcsDirectoryMapping child) {
|
||||
if (! parent.getVcs().equals(child.getVcs())) return false;
|
||||
|
||||
final String parentPath = parent.systemIndependentPath();
|
||||
final String fixedParentPath = (parentPath.endsWith("/")) ? parentPath : (parentPath + "/");
|
||||
|
||||
if (child.systemIndependentPath().length() < fixedParentPath.length()) {
|
||||
return child.systemIndependentPath().equals(parentPath);
|
||||
}
|
||||
return child.systemIndependentPath().startsWith(fixedParentPath);
|
||||
}
|
||||
|
||||
public List<LocalFileSystem.WatchRequest> getRemovedRequests() {
|
||||
return myRemovedRequests;
|
||||
}
|
||||
}
|
||||
|
||||
// todo area for optimization
|
||||
private List<LocalFileSystem.WatchRequest> removeRedundantMappings() {
|
||||
final Set<Map.Entry<String, List<VcsDirectoryMapping>>> entries = myVcsToPaths.entrySet();
|
||||
|
||||
private void removeRedundantMappings() {
|
||||
final LocalFileSystem lfs = LocalFileSystem.getInstance();
|
||||
final AllVcsesI allVcses = AllVcses.getInstance(myProject);
|
||||
|
||||
final List<LocalFileSystem.WatchRequest> removedRequests = new LinkedList<LocalFileSystem.WatchRequest>();
|
||||
|
||||
for (Iterator<String> iterator = myVcsToPaths.keySet().iterator(); iterator.hasNext();) {
|
||||
final String vcsName = iterator.next();
|
||||
final List<VcsDirectoryMapping> mappings = myVcsToPaths.get(vcsName);
|
||||
@@ -456,9 +394,6 @@ public class NewMappings {
|
||||
|
||||
// to calculate what had been removed
|
||||
mappings.removeAll(filteredMappings);
|
||||
for (VcsDirectoryMapping mapping : mappings) {
|
||||
removedRequests.add(myDirectoryMappingWatches.remove(mapping));
|
||||
}
|
||||
|
||||
if (filteredMappings.isEmpty()) {
|
||||
iterator.remove();
|
||||
@@ -469,7 +404,6 @@ public class NewMappings {
|
||||
}
|
||||
|
||||
sortedMappingsByMap();
|
||||
return removedRequests;
|
||||
}
|
||||
|
||||
private boolean trySwitchVcs(final String path, final String activeVcsName) {
|
||||
@@ -525,14 +459,6 @@ public class NewMappings {
|
||||
return newList;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static LocalFileSystem.WatchRequest addWatchRequest(final VcsDirectoryMapping mapping) {
|
||||
if (! mapping.isDefaultMapping()) {
|
||||
return LocalFileSystem.getInstance().addRootToWatch(mapping.getDirectory(), true);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class MyMappingsComparator implements Comparator<VcsDirectoryMapping> {
|
||||
private static final MyMappingsComparator ourInstance = new MyMappingsComparator();
|
||||
|
||||
@@ -628,7 +554,6 @@ public class NewMappings {
|
||||
private static class MySetMappingsPreProcessor {
|
||||
private final List<VcsDirectoryMapping> myItems;
|
||||
private List<VcsDirectoryMapping> myItemsCopy;
|
||||
private Map<VcsDirectoryMapping, LocalFileSystem.WatchRequest> myRequests;
|
||||
|
||||
public MySetMappingsPreProcessor(final List<VcsDirectoryMapping> items) {
|
||||
myItems = items;
|
||||
@@ -638,23 +563,10 @@ public class NewMappings {
|
||||
return myItemsCopy;
|
||||
}
|
||||
|
||||
public Map<VcsDirectoryMapping, LocalFileSystem.WatchRequest> getRequests() {
|
||||
return myRequests;
|
||||
}
|
||||
|
||||
public void invoke() {
|
||||
if (myItems.isEmpty()) {
|
||||
myItemsCopy = Collections.singletonList(new VcsDirectoryMapping("", ""));
|
||||
myRequests = Collections.emptyMap();
|
||||
} else {
|
||||
myRequests = new HashMap<VcsDirectoryMapping, LocalFileSystem.WatchRequest>();
|
||||
|
||||
for (VcsDirectoryMapping item : myItems) {
|
||||
final LocalFileSystem.WatchRequest request = addWatchRequest(item);
|
||||
if (request != null) {
|
||||
myRequests.put(item, request);
|
||||
}
|
||||
}
|
||||
myItemsCopy = myItems;
|
||||
}
|
||||
}
|
||||
@@ -662,4 +574,5 @@ public class NewMappings {
|
||||
|
||||
private @interface Modification {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user