From 4bef55acec2b7d3b01ae7bd46bf05ceffa2fb29e Mon Sep 17 00:00:00 2001 From: irengrig Date: Sat, 19 Dec 2009 18:16:54 +0300 Subject: [PATCH] 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.) --- .../openapi/vcs/impl/ModuleVcsDetector.java | 75 +++++++++++++++++----- .../vcs/impl/projectlevelman/NewMappings.java | 10 +++ .../src/org/jetbrains/idea/svn/SvnUtil.java | 22 +++++++ .../src/org/jetbrains/idea/svn/SvnVcs.java | 18 +++++- 4 files changed, 105 insertions(+), 20 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/openapi/vcs/impl/ModuleVcsDetector.java b/platform/lang-impl/src/com/intellij/openapi/vcs/impl/ModuleVcsDetector.java index 6002443fdd..7fec28d156 100644 --- a/platform/lang-impl/src/com/intellij/openapi/vcs/impl/ModuleVcsDetector.java +++ b/platform/lang-impl/src/com/intellij/openapi/vcs/impl/ModuleVcsDetector.java @@ -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 usedVcses = new HashSet(); Map vcsMap = new HashMap(); - 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 contentRoots = new HashSet(); + 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 vcsDirectoryMappings = new ArrayList(myVcsManager.getDirectoryMappings()); + for (Iterator 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 entry: vcsMap.entrySet()) { myVcsManager.setAutoDirectoryMapping(entry.getKey().getPath(), entry.getValue() == null ? "" : entry.getValue().getName()); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/projectlevelman/NewMappings.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/projectlevelman/NewMappings.java index 9f398b810d..cca8b1bb7f 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/projectlevelman/NewMappings.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/projectlevelman/NewMappings.java @@ -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 vcsDirectoryMappings = myVcsToPaths.get(activeVcsName); + if ((vcsDirectoryMappings != null) && (vcsDirectoryMappings.contains(newMapping))) { + return; + } + } + + } final LocalFileSystem.WatchRequest request = addWatchRequest(newMapping); final Ref switched = new Ref(Boolean.FALSE); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java index cb9142fab1..d507e645f5 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java @@ -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; + } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java index 104ce450d1..0af67480be 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java @@ -877,22 +877,34 @@ public class SvnVcs extends AbstractVcs { final List> infos = new ArrayList>(in.size()); final SvnFileUrlMappingImpl mapping = (SvnFileUrlMappingImpl) getSvnFileUrlMapping(); + final List notMatched = new LinkedList(); 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(vf, url.toString(), s)); } final List> filtered = new ArrayList>(infos.size()); ForNestedRootChecker.filterOutSuperfluousChildren(this, infos, filtered); - return ObjectsConvertor.convert(filtered, new Convertor, S>() { + final List converted = ObjectsConvertor.convert(filtered, new Convertor, S>() { public S convert(final MyPair 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 implements RootUrlPair { -- 2.11.4.GIT