VCS: roots autodetection mentioned in IDEADEV-42024 (Subversion: Update is not working properly) and IDEA-25305 (After adding a new maven module, my Version COntrol configuration is cleared.)

This commit is contained in:
irengrig
2009-12-19 18:16:54 +03:00
parent e3afc48202
commit 4bef55acec
4 changed files with 105 additions and 20 deletions
@@ -24,6 +24,8 @@ import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.ModuleAdapter;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleRootEvent;
import com.intellij.openapi.roots.ModuleRootListener;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.ui.Messages;
@@ -34,13 +36,11 @@ import com.intellij.openapi.vcs.VcsBundle;
import com.intellij.openapi.vcs.VcsDirectoryMapping;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.messages.MessageBus;
import com.intellij.util.messages.MessageBusConnection;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.*;
/**
* @author yole
@@ -49,6 +49,7 @@ public class ModuleVcsDetector implements ProjectComponent {
private final Project myProject;
private final MessageBus myMessageBus;
private final ProjectLevelVcsManagerImpl myVcsManager;
private MessageBusConnection myConnection;
public ModuleVcsDetector(final Project project, final MessageBus messageBus, final ProjectLevelVcsManager vcsManager) {
myProject = project;
@@ -63,7 +64,7 @@ public class ModuleVcsDetector implements ProjectComponent {
manager.registerStartupActivity(new Runnable() {
public void run() {
if (myVcsManager.needAutodetectMappings()) {
autoDetectVcsMappings();
autoDetectVcsMappings(true);
}
myVcsManager.updateActiveVcss();
}
@@ -71,20 +72,36 @@ public class ModuleVcsDetector implements ProjectComponent {
manager.registerPostStartupActivity(new Runnable() {
public void run() {
if (myMessageBus != null) {
myMessageBus.connect().subscribe(ProjectTopics.MODULES, new ModuleAdapter() {
public void moduleAdded(final Project project, final Module module) {
autoDetectModuleVcsMapping(module);
}
public void beforeModuleRemoved(final Project project, final Module module) {
checkRemoveVcsRoot(module);
}
});
myConnection = myMessageBus.connect();
final MyModulesListener listener = new MyModulesListener();
myConnection.subscribe(ProjectTopics.MODULES, listener);
myConnection.subscribe(ProjectTopics.PROJECT_ROOTS, listener);
}
}
});
}
private class MyModulesListener extends ModuleAdapter implements ModuleRootListener {
public void beforeRootsChange(ModuleRootEvent event) {
}
public void rootsChanged(ModuleRootEvent event) {
// the check calculates to true only before user has done any change to mappings, i.e. in case modules are detected/added automatically
// on start etc (look inside)
if (myVcsManager.needAutodetectMappings()) {
autoDetectVcsMappings(false);
}
}
public void moduleAdded(final Project project, final Module module) {
autoDetectModuleVcsMapping(module);
}
public void beforeModuleRemoved(final Project project, final Module module) {
checkRemoveVcsRoot(module);
}
}
public void projectClosed() {
}
@@ -98,12 +115,16 @@ public class ModuleVcsDetector implements ProjectComponent {
}
public void disposeComponent() {
if (myConnection != null) {
myConnection.disconnect();
}
}
private void autoDetectVcsMappings() {
private void autoDetectVcsMappings(final boolean tryMapPieces) {
Set<AbstractVcs> usedVcses = new HashSet<AbstractVcs>();
Map<VirtualFile, AbstractVcs> vcsMap = new HashMap<VirtualFile, AbstractVcs>();
for(Module module: ModuleManager.getInstance(myProject).getModules()) {
final ModuleManager moduleManager = ModuleManager.getInstance(myProject);
for(Module module: moduleManager.getModules()) {
final VirtualFile[] files = ModuleRootManager.getInstance(module).getContentRoots();
for(VirtualFile file: files) {
AbstractVcs contentRootVcs = myVcsManager.findVersioningVcs(file);
@@ -115,11 +136,31 @@ public class ModuleVcsDetector implements ProjectComponent {
}
if (usedVcses.size() == 1) {
final AbstractVcs[] abstractVcses = usedVcses.toArray(new AbstractVcs[1]);
final Module[] modules = moduleManager.getModules();
final Set<String> contentRoots = new HashSet<String>();
for (Module module : modules) {
final VirtualFile[] roots = ModuleRootManager.getInstance(module).getContentRoots();
for (VirtualFile root : roots) {
contentRoots.add(root.getPath());
}
}
if (abstractVcses [0] != null) {
final List<VcsDirectoryMapping> vcsDirectoryMappings = new ArrayList<VcsDirectoryMapping>(myVcsManager.getDirectoryMappings());
for (Iterator<VcsDirectoryMapping> iterator = vcsDirectoryMappings.iterator(); iterator.hasNext();) {
final VcsDirectoryMapping mapping = iterator.next();
if (! contentRoots.contains(mapping.getDirectory())) {
iterator.remove();
}
}
myVcsManager.setAutoDirectoryMapping("", abstractVcses [0].getName());
for (VcsDirectoryMapping mapping : vcsDirectoryMappings) {
myVcsManager.removeDirectoryMapping(mapping);
}
myVcsManager.cleanupMappings();
}
}
else {
else if (tryMapPieces) {
for(Map.Entry<VirtualFile, AbstractVcs> entry: vcsMap.entrySet()) {
myVcsManager.setAutoDirectoryMapping(entry.getKey().getPath(), entry.getValue() == null ? "" : entry.getValue().getName());
}
@@ -100,6 +100,16 @@ public class NewMappings {
public void setMapping(final String path, final String activeVcsName) {
LOG.debug("setMapping path = '" + path + "' vcs = " + activeVcsName);
final VcsDirectoryMapping newMapping = new VcsDirectoryMapping(path, activeVcsName);
// do not add duplicates
synchronized (myLock) {
if (myVcsToPaths.containsKey(activeVcsName)) {
final List<VcsDirectoryMapping> vcsDirectoryMappings = myVcsToPaths.get(activeVcsName);
if ((vcsDirectoryMappings != null) && (vcsDirectoryMappings.contains(newMapping))) {
return;
}
}
}
final LocalFileSystem.WatchRequest request = addWatchRequest(newMapping);
final Ref<Boolean> switched = new Ref<Boolean>(Boolean.FALSE);
@@ -39,6 +39,8 @@ import org.jetbrains.idea.svn.dialogs.WCInfo;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.internal.wc.SVNFileUtil;
import org.tmatesoft.svn.core.internal.wc.admin.SVNEntry;
import org.tmatesoft.svn.core.internal.wc.admin.SVNWCAccess;
import org.tmatesoft.svn.core.io.SVNCapability;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.wc.*;
@@ -582,4 +584,24 @@ public class SvnUtil {
}
return false;
}
@Nullable
public static SVNURL getUrl(final File file) {
SVNWCAccess wcAccess = SVNWCAccess.newInstance(null);
try {
wcAccess.probeOpen(file, false, 0);
SVNEntry entry = wcAccess.getVersionedEntry(file, false);
return entry.getSVNURL();
} catch (SVNException e) {
//
} finally {
try {
wcAccess.close();
}
catch (SVNException e) {
//
}
}
return null;
}
}
@@ -877,22 +877,34 @@ public class SvnVcs extends AbstractVcs {
final List<MyPair<S>> infos = new ArrayList<MyPair<S>>(in.size());
final SvnFileUrlMappingImpl mapping = (SvnFileUrlMappingImpl) getSvnFileUrlMapping();
final List<S> notMatched = new LinkedList<S>();
for (S s : in) {
final VirtualFile vf = convertor.convert(s);
final File ioFile = new File(vf.getPath());
final SVNURL url = mapping.getUrlForFile(ioFile);
if (url == null) continue;
SVNURL url = mapping.getUrlForFile(ioFile);
if (url == null) {
url = SvnUtil.getUrl(ioFile);
if (url == null) {
notMatched.add(s);
continue;
}
}
infos.add(new MyPair<S>(vf, url.toString(), s));
}
final List<MyPair<S>> filtered = new ArrayList<MyPair<S>>(infos.size());
ForNestedRootChecker.filterOutSuperfluousChildren(this, infos, filtered);
return ObjectsConvertor.convert(filtered, new Convertor<MyPair<S>, S>() {
final List<S> converted = ObjectsConvertor.convert(filtered, new Convertor<MyPair<S>, S>() {
public S convert(final MyPair<S> o) {
return o.getSrc();
}
});
if (! notMatched.isEmpty()) {
// potential bug is here: order is not kept. but seems it only occurs for cases where result is sorted after filtering so ok
converted.addAll(notMatched);
}
return converted;
}
private static class MyPair<T> implements RootUrlPair {