IDEA-26360 (Performance and inconsistency issues with svn:externals and "Detect neste...
[fedora-idea.git] / plugins / svn4idea / src / org / jetbrains / idea / svn / RootsToWorkingCopies.java
blobacac8c25cfafc69c7709f721a81f30cf7b128205
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org.jetbrains.idea.svn;
18 import com.intellij.openapi.application.ApplicationManager;
19 import com.intellij.openapi.progress.BackgroundTaskQueue;
20 import com.intellij.openapi.progress.ProgressIndicator;
21 import com.intellij.openapi.progress.Task;
22 import com.intellij.openapi.project.Project;
23 import com.intellij.openapi.vcs.CalledInBackground;
24 import com.intellij.openapi.vcs.ProjectLevelVcsManager;
25 import com.intellij.openapi.vcs.VcsListener;
26 import com.intellij.openapi.vcs.changes.BackgroundFromStartOption;
27 import com.intellij.openapi.vfs.VirtualFile;
28 import org.jetbrains.annotations.NotNull;
29 import org.jetbrains.annotations.Nullable;
30 import org.tmatesoft.svn.core.SVNException;
31 import org.tmatesoft.svn.core.SVNURL;
32 import org.tmatesoft.svn.core.internal.util.SVNURLUtil;
33 import org.tmatesoft.svn.core.internal.wc.admin.SVNEntry;
34 import org.tmatesoft.svn.core.internal.wc.admin.SVNWCAccess;
35 import org.tmatesoft.svn.core.wc.SVNWCUtil;
37 import java.io.File;
38 import java.util.*;
40 // 1. listen to roots changes
41 // 2. - possibly - to deletion/checkouts??? what if WC roots can be
42 public class RootsToWorkingCopies implements VcsListener {
43 private final Object myLock;
44 private final Map<VirtualFile, WorkingCopy> myRootMapping;
45 private final Set<VirtualFile> myUnversioned;
46 private final BackgroundTaskQueue myQueue;
47 private final Project myProject;
49 public RootsToWorkingCopies(final Project project) {
50 myProject = project;
51 myQueue = new BackgroundTaskQueue(project, "SVN VCS roots authorization checker");
52 myLock = new Object();
53 myRootMapping = new HashMap<VirtualFile, WorkingCopy>();
54 myUnversioned = new HashSet<VirtualFile>();
57 public void addRoot(final VirtualFile root) {
58 myQueue.run(new Task.Backgroundable(myProject, "Looking for '" + root.getPath() + "' working copy root", false,
59 BackgroundFromStartOption.getInstance()) {
60 @Override
61 public void run(@NotNull ProgressIndicator indicator) {
62 calculateRoot(root);
64 });
67 @Nullable
68 @CalledInBackground
69 public WorkingCopy getMatchingCopy(final SVNURL url) {
70 assert ! ApplicationManager.getApplication().isDispatchThread();
72 final VirtualFile[] roots = ProjectLevelVcsManager.getInstance(myProject).getRootsUnderVcs(SvnVcs.getInstance(myProject));
73 synchronized (myLock) {
74 for (VirtualFile root : roots) {
75 final WorkingCopy wcRoot = getWcRoot(root);
76 if (wcRoot != null) {
77 final SVNURL common = SVNURLUtil.getCommonURLAncestor(wcRoot.getUrl(), url);
78 if (wcRoot.getUrl().equals(common) || url.equals(common)) {
79 return wcRoot;
84 return null;
87 @CalledInBackground
88 @Nullable
89 public WorkingCopy getWcRoot(final VirtualFile root) {
90 assert ! ApplicationManager.getApplication().isDispatchThread();
92 synchronized (myLock) {
93 if (myUnversioned.contains(root)) return null;
94 final WorkingCopy existing = myRootMapping.get(root);
95 if (existing != null) return existing;
97 return calculateRoot(root);
100 @Nullable
101 private WorkingCopy calculateRoot(final VirtualFile root) {
102 WorkingCopy workingCopy = null;
103 try {
104 final File workingCopyRoot = SVNWCUtil.getWorkingCopyRoot(new File(root.getPath()), true);
105 if (workingCopyRoot != null) {
106 SVNWCAccess wcAccess = SVNWCAccess.newInstance(null);
107 try {
108 wcAccess.probeOpen(workingCopyRoot, false, 0);
109 SVNEntry entry = wcAccess.getVersionedEntry(workingCopyRoot, false);
110 final SVNURL url = entry.getSVNURL();
111 if (url != null) {
112 workingCopy = new WorkingCopy(workingCopyRoot, url);
114 } finally {
115 wcAccess.close();
119 catch (SVNException e) {
122 synchronized (myLock) {
123 if (workingCopy == null) {
124 myRootMapping.remove(root);
125 myUnversioned.add(root);
126 } else {
127 myUnversioned.remove(root);
128 myRootMapping.put(root, workingCopy);
131 return workingCopy;
134 public void clear() {
135 synchronized (myLock) {
136 myRootMapping.clear();
137 myUnversioned.clear();
141 public void directoryMappingChanged() {
142 final SvnVcs svnVcs = SvnVcs.getInstance(myProject);
143 // todo +- here... shouldnt be
144 svnVcs.getAuthNotifier().clear();
146 final VirtualFile[] roots = ProjectLevelVcsManager.getInstance(myProject).getRootsUnderVcs(svnVcs);
147 synchronized (myLock) {
148 clear();
149 for (VirtualFile root : roots) {
150 addRoot(root);