From d1608349b89fb8844cb6f8adbcd4948676528f23 Mon Sep 17 00:00:00 2001 From: irengrig Date: Wed, 12 Dec 2012 18:49:59 +0400 Subject: [PATCH] IDEA-16732 Externally svn switched sources not detected by IDEA --- .../idea/svn/NestedCopiesBuilder.java | 17 +++++- .../jetbrains/idea/svn/StatusReceiver.java | 2 +- .../jetbrains/idea/svn/SvnChangeProvider.java | 2 +- .../idea/svn/SvnChangeProviderContext.java | 4 ++ .../idea/svn/SvnRecursiveStatusWalker.java | 8 ++- .../svn/SvnExternalCommitNoticedTest.java | 51 ++++++++++++++++++ .../svn16/SvnExternalCommitNoticedTest.java | 54 ++++++++++++++++++- 7 files changed, 131 insertions(+), 7 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/NestedCopiesBuilder.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/NestedCopiesBuilder.java index 1a4e514a2ca5..b811bf888a50 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/NestedCopiesBuilder.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/NestedCopiesBuilder.java @@ -15,6 +15,8 @@ */ package org.jetbrains.idea.svn; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vcs.FilePath; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; @@ -29,8 +31,12 @@ import java.util.Set; public class NestedCopiesBuilder implements StatusReceiver { private final Set mySet; + private final Project myProject; + private final SvnFileUrlMapping myMapping; - public NestedCopiesBuilder() { + public NestedCopiesBuilder(final Project project, final SvnFileUrlMapping mapping) { + myProject = project; + myMapping = mapping; mySet = new HashSet(); } @@ -67,6 +73,15 @@ public class NestedCopiesBuilder implements StatusReceiver { mySet.add(info); } + @Override + public void bewareRoot(VirtualFile vf, SVNURL url, WorkingCopyFormat copyFormat) { + final File ioFile = new File(vf.getPath()); + final RootUrlInfo info = myMapping.getWcRootForFilePath(ioFile); + if (info != null && FileUtil.filesEqual(ioFile, info.getIoFile()) && ! info.getAbsoluteUrlAsUrl().equals(url)) { + SvnVcs.getInstance(myProject).invokeRefreshSvnRoots(true); + } + } + static class MyPointInfo { private final VirtualFile myFile; private SVNURL myUrl; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/StatusReceiver.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/StatusReceiver.java index 1cd827424c8e..d89fff56efe5 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/StatusReceiver.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/StatusReceiver.java @@ -21,7 +21,6 @@ import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.wc.SVNStatus; -import java.io.File; import java.util.EventListener; public interface StatusReceiver extends EventListener { @@ -29,4 +28,5 @@ public interface StatusReceiver extends EventListener { void processIgnored(final VirtualFile vFile); void processUnversioned(final VirtualFile vFile); void processCopyRoot(VirtualFile file, SVNURL url, WorkingCopyFormat format); + void bewareRoot(VirtualFile vf, SVNURL url, WorkingCopyFormat copyFormat); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnChangeProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnChangeProvider.java index d8229828910a..fe4a640650d6 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnChangeProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnChangeProvider.java @@ -79,7 +79,7 @@ public class SvnChangeProvider implements ChangeProvider { final SvnChangeProviderContext context = new SvnChangeProviderContext(myVcs, builder, progress); final StatusWalkerPartnerImpl partner = new StatusWalkerPartnerImpl(myVcs, progress); - final NestedCopiesBuilder nestedCopiesBuilder = new NestedCopiesBuilder(); + final NestedCopiesBuilder nestedCopiesBuilder = new NestedCopiesBuilder(myVcs.getProject(), mySvnFileUrlMapping); final EventDispatcher statusReceiver = EventDispatcher.create(StatusReceiver.class); statusReceiver.addListener(context); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnChangeProviderContext.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnChangeProviderContext.java index 04b410566749..ab0202090eb8 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnChangeProviderContext.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnChangeProviderContext.java @@ -73,6 +73,10 @@ class SvnChangeProviderContext implements StatusReceiver { public void processCopyRoot(VirtualFile file, SVNURL url, WorkingCopyFormat format) { } + @Override + public void bewareRoot(VirtualFile vf, SVNURL url, WorkingCopyFormat copyFormat) { + } + public ChangelistBuilder getBuilder() { return myChangelistBuilder; } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnRecursiveStatusWalker.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnRecursiveStatusWalker.java index 1ccf03b7c8ef..61c487ff94c1 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnRecursiveStatusWalker.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnRecursiveStatusWalker.java @@ -247,9 +247,13 @@ public class SvnRecursiveStatusWalker { if (SVNStatusType.OBSTRUCTED.equals(status) || SVNStatusType.STATUS_NONE.equals(status)) { return; } - if (vf != null && myCurrentItem.isIsInnerCopyRoot()) { - myReceiver.processCopyRoot(vf, statusInner.getURL(), + if (vf != null) { + if (myCurrentItem.isIsInnerCopyRoot()) { + myReceiver.processCopyRoot(vf, statusInner.getURL(), WorkingCopyFormat.getInstance(statusInner.getWorkingCopyFormat())); + } else { + myReceiver.bewareRoot(vf, statusInner.getURL(), WorkingCopyFormat.getInstance(statusInner.getWorkingCopyFormat())); + } } } } diff --git a/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnExternalCommitNoticedTest.java b/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnExternalCommitNoticedTest.java index 5999b33b527a..d583a942fbbd 100644 --- a/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnExternalCommitNoticedTest.java +++ b/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnExternalCommitNoticedTest.java @@ -15,6 +15,7 @@ */ package org.jetbrains.idea.svn; +import com.intellij.openapi.vcs.FileStatus; import com.intellij.openapi.vcs.VcsConfiguration; import com.intellij.openapi.vcs.changes.ChangeListManager; import com.intellij.openapi.vcs.changes.ChangeListManagerImpl; @@ -27,6 +28,7 @@ import org.junit.Before; import org.junit.Test; import java.io.File; +import java.util.List; /** * Created with IntelliJ IDEA. @@ -107,6 +109,55 @@ public class SvnExternalCommitNoticedTest extends Svn17TestCase { Assert.assertEquals(0, clManager.getChangesIn(myWorkingCopyDir).size()); } + @Test + public void testExternalSwitch() throws Exception { + final String branchUrl = prepareBranchesStructure(); + final SubTree tree = new SubTree(myWorkingCopyDir); + + verify(runSvn("switch", branchUrl + "/root/source/s1.txt", tree.myS1File.getPath())); + verify(runSvn("switch", branchUrl + "/root/target", tree.myTargetDir.getPath())); + + myWorkingCopyDir.refresh(false, true); + imitateEvent(myWorkingCopyDir); + // no dirty scope externally provided! just VFS refresh + clManager.ensureUpToDate(false); + + Assert.assertEquals(FileStatus.SWITCHED, clManager.getStatus(tree.myS1File)); + Assert.assertEquals(FileStatus.NOT_CHANGED, clManager.getStatus(tree.myS2File)); + Assert.assertEquals(FileStatus.NOT_CHANGED, clManager.getStatus(tree.mySourceDir)); + Assert.assertEquals(FileStatus.SWITCHED, clManager.getStatus(tree.myTargetDir)); + Assert.assertEquals(FileStatus.SWITCHED, clManager.getStatus(tree.myTargetFiles.get(1))); + } + + @Test + public void testExternalRootSwitch() throws Exception { + final String branchUrl = prepareBranchesStructure(); + final SubTree tree = new SubTree(myWorkingCopyDir); + + SvnConfiguration.getInstance(myProject).DETECT_NESTED_COPIES = true; + myVcs.invokeRefreshSvnRoots(false); + clManager.ensureUpToDate(false); + clManager.ensureUpToDate(false); + SvnFileUrlMapping workingCopies = myVcs.getSvnFileUrlMapping(); + List infos = workingCopies.getAllWcInfos(); + Assert.assertEquals(1, infos.size()); + Assert.assertEquals(myRepoUrl + "/trunk", infos.get(0).getAbsoluteUrl()); + + verify(runSvn("switch", branchUrl, myWorkingCopyDir.getPath())); + + myWorkingCopyDir.refresh(false, true); + imitateEvent(myWorkingCopyDir); + sleep(300); + // no dirty scope externally provided! just VFS refresh + clManager.ensureUpToDate(false); + clManager.ensureUpToDate(false); //first run queries one more update + + workingCopies = myVcs.getSvnFileUrlMapping(); + infos = workingCopies.getAllWcInfos(); + Assert.assertEquals(1, infos.size()); + Assert.assertEquals(branchUrl, infos.get(0).getAbsoluteUrl()); + } + @Test public void testExternalCommitInExternals() throws Exception { prepareExternal(); diff --git a/plugins/svn4idea/testSource/org/jetbrains/idea/svn16/SvnExternalCommitNoticedTest.java b/plugins/svn4idea/testSource/org/jetbrains/idea/svn16/SvnExternalCommitNoticedTest.java index 87f4caf57467..46345d712b9e 100644 --- a/plugins/svn4idea/testSource/org/jetbrains/idea/svn16/SvnExternalCommitNoticedTest.java +++ b/plugins/svn4idea/testSource/org/jetbrains/idea/svn16/SvnExternalCommitNoticedTest.java @@ -15,6 +15,7 @@ */ package org.jetbrains.idea.svn16; +import com.intellij.openapi.vcs.FileStatus; import com.intellij.openapi.vcs.VcsConfiguration; import com.intellij.openapi.vcs.changes.ChangeListManager; import com.intellij.openapi.vcs.changes.ChangeListManagerImpl; @@ -22,13 +23,13 @@ import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.impl.local.FileWatcher; -import org.jetbrains.idea.svn.Svn17TestCase; -import org.jetbrains.idea.svn.SvnVcs; +import org.jetbrains.idea.svn.*; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import java.io.File; +import java.util.List; /** * Created with IntelliJ IDEA. @@ -109,6 +110,55 @@ public class SvnExternalCommitNoticedTest extends Svn17TestCase { Assert.assertEquals(0, clManager.getChangesIn(myWorkingCopyDir).size()); } + @Test + public void testExternalSwitch() throws Exception { + final String branchUrl = prepareBranchesStructure(); + final SubTree tree = new SubTree(myWorkingCopyDir); + + verify(runSvn("switch", branchUrl + "/root/source/s1.txt", tree.myS1File.getPath())); + verify(runSvn("switch", branchUrl + "/root/target", tree.myTargetDir.getPath())); + + myWorkingCopyDir.refresh(false, true); + imitateEvent(myWorkingCopyDir); + // no dirty scope externally provided! just VFS refresh + clManager.ensureUpToDate(false); + + Assert.assertEquals(FileStatus.SWITCHED, clManager.getStatus(tree.myS1File)); + Assert.assertEquals(FileStatus.NOT_CHANGED, clManager.getStatus(tree.myS2File)); + Assert.assertEquals(FileStatus.NOT_CHANGED, clManager.getStatus(tree.mySourceDir)); + Assert.assertEquals(FileStatus.SWITCHED, clManager.getStatus(tree.myTargetDir)); + Assert.assertEquals(FileStatus.SWITCHED, clManager.getStatus(tree.myTargetFiles.get(1))); + } + + @Test + public void testExternalRootSwitch() throws Exception { + final String branchUrl = prepareBranchesStructure(); + final SubTree tree = new SubTree(myWorkingCopyDir); + + SvnConfiguration.getInstance(myProject).DETECT_NESTED_COPIES = true; + myVcs.invokeRefreshSvnRoots(false); + clManager.ensureUpToDate(false); + clManager.ensureUpToDate(false); + SvnFileUrlMapping workingCopies = myVcs.getSvnFileUrlMapping(); + List infos = workingCopies.getAllWcInfos(); + Assert.assertEquals(1, infos.size()); + Assert.assertEquals(myRepoUrl + "/trunk", infos.get(0).getAbsoluteUrl()); + + verify(runSvn("switch", branchUrl, myWorkingCopyDir.getPath())); + + myWorkingCopyDir.refresh(false, true); + imitateEvent(myWorkingCopyDir); + sleep(300); + // no dirty scope externally provided! just VFS refresh + clManager.ensureUpToDate(false); + clManager.ensureUpToDate(false); //first run queries one more update + + workingCopies = myVcs.getSvnFileUrlMapping(); + infos = workingCopies.getAllWcInfos(); + Assert.assertEquals(1, infos.size()); + Assert.assertEquals(branchUrl, infos.get(0).getAbsoluteUrl()); + } + @Test public void testExternalCommitInExternals() throws Exception { prepareExternal();