diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java index e4aa6b3f2da1..0c441e2af3fa 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java @@ -26,10 +26,7 @@ import org.jetbrains.idea.svn.portable.SvnExceptionWrapper; import org.jetbrains.idea.svn.portable.SvnStatusClientI; import org.tmatesoft.svn.core.*; import org.tmatesoft.svn.core.internal.util.SVNPathUtil; -import org.tmatesoft.svn.core.wc.ISVNStatusHandler; -import org.tmatesoft.svn.core.wc.SVNInfo; -import org.tmatesoft.svn.core.wc.SVNRevision; -import org.tmatesoft.svn.core.wc.SVNStatus; +import org.tmatesoft.svn.core.wc.*; import org.xml.sax.SAXException; import javax.xml.parsers.ParserConfigurationException; @@ -39,6 +36,8 @@ import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.util.Collection; +import java.util.HashMap; +import java.util.Map; /** * Created with IntelliJ IDEA. @@ -101,62 +100,10 @@ public class SvnCommandLineStatusClient implements SvnStatusClientI { // todo can not understand why revision can be used here final SvnSimpleCommand command = new SvnSimpleCommand(myProject, base, SvnCommandName.st); + putParameters(depth, remote, reportAll, includeIgnored, changeLists, command); - if (depth != null) { - command.addParameters("--depth", depth.getName()); - } - if (remote) { - command.addParameters("-u"); - } - if (reportAll) { - command.addParameters("-v"); - } - if (includeIgnored) { - command.addParameters("--no-ignore"); - } - // no way in interface to ignore externals - /*if (! collectParentExternals) { - command.addParameters("--ignore-externals"); - }*/ - - //--changelist (--cl) ARG - changelistsToCommand(changeLists, command); - command.addParameters("--xml"); - - final String[] changelistName = new String[1]; final SvnStatusHandler[] svnHandl = new SvnStatusHandler[1]; - svnHandl[0] = new SvnStatusHandler(new SvnStatusHandler.ExternalDataCallback() { - @Override - public void switchPath() { - final PortableStatus pending = svnHandl[0].getPending(); - pending.setChangelistName(changelistName[0]); - try { - if (infoBase != null) { - final String append = SVNPathUtil.append(infoBase.getURL().toString(), FileUtil.toSystemIndependentName(pending.getPath())); - pending.setURL(SVNURL.parseURIEncoded(append)); - } - handler.handleStatus(pending); - } - catch (SVNException e) { - throw new SvnExceptionWrapper(e); - } - } - - @Override - public void switchChangeList(String newList) { - changelistName[0] = newList; - } - }, base, new Convertor() { - @Override - public SVNInfo convert(File o) { - try { - return myInfoClient.doInfo(o, revision); - } - catch (SVNException e) { - throw new SvnExceptionWrapper(e); - } - } - }); + svnHandl[0] = createStatusHandler(revision, handler, base, infoBase, svnHandl); try { final String result = command.run(); @@ -185,6 +132,109 @@ public class SvnCommandLineStatusClient implements SvnStatusClientI { return 0; } + private void putParameters(SVNDepth depth, + boolean remote, + boolean reportAll, + boolean includeIgnored, + Collection changeLists, + SvnSimpleCommand command) { + if (depth != null) { + command.addParameters("--depth", depth.getName()); + } + if (remote) { + command.addParameters("-u"); + } + if (reportAll) { + command.addParameters("-v"); + } + if (includeIgnored) { + command.addParameters("--no-ignore"); + } + // no way in interface to ignore externals + /*if (! collectParentExternals) { + command.addParameters("--ignore-externals"); + }*/ + + //--changelist (--cl) ARG + changelistsToCommand(changeLists, command); + command.addParameters("--xml"); + } + + public SvnStatusHandler createStatusHandler(final SVNRevision revision, + final ISVNStatusHandler handler, + final File base, + final SVNInfo infoBase, final SvnStatusHandler[] svnHandl) { + final SvnStatusHandler.ExternalDataCallback callback = createStatusCallback(handler, base, infoBase, svnHandl); + + return new SvnStatusHandler(callback, base, new Convertor() { + @Override + public SVNInfo convert(File o) { + try { + return myInfoClient.doInfo(o, revision); + } + catch (SVNException e) { + throw new SvnExceptionWrapper(e); + } + } + }); + } + + public static SvnStatusHandler.ExternalDataCallback createStatusCallback(final ISVNStatusHandler handler, + final File base, + final SVNInfo infoBase, + final SvnStatusHandler[] svnHandl) { + final Map externalsMap = new HashMap(); + final String[] changelistName = new String[1]; + + return new SvnStatusHandler.ExternalDataCallback() { + @Override + public void switchPath() { + final PortableStatus pending = svnHandl[0].getPending(); + pending.setChangelistName(changelistName[0]); + try { + //if (infoBase != null) { + SVNInfo baseInfo = infoBase; + File baseFile = base; + final File pendingFile = new File(pending.getPath()); + if (! externalsMap.isEmpty()) { + for (File file : externalsMap.keySet()) { + if (FileUtil.isAncestor(file, pendingFile, false)) { + baseInfo = externalsMap.get(file); + baseFile = file; + break; + } + } + } + if (baseInfo != null) { + final String append; + final String systemIndependentPath = FileUtil.toSystemIndependentName(pending.getPath()); + if (pendingFile.isAbsolute()) { + final String relativePath = + FileUtil.getRelativePath(FileUtil.toSystemIndependentName(baseFile.getPath()), systemIndependentPath, '/'); + append = SVNPathUtil.append(baseInfo.getURL().toString(), FileUtil.toSystemIndependentName(relativePath)); + } + else { + append = SVNPathUtil.append(baseInfo.getURL().toString(), systemIndependentPath); + } + pending.setURL(SVNURL.parseURIEncoded(append)); + } + if (SVNStatusType.STATUS_EXTERNAL.equals(pending.getNodeStatus())) { + externalsMap.put(pending.getFile(), pending.getInfo()); + } + handler.handleStatus(pending); + } + catch (SVNException e) { + throw new SvnExceptionWrapper(e); + } + } + + @Override + public void switchChangeList(String newList) { + changelistName[0] = newList; + } + }; + } + public static void changelistsToCommand(Collection changeLists, SvnSimpleCommand command) { if (changeLists != null) { for (Object o : changeLists) { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/portable/PortableStatus.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/portable/PortableStatus.java index 667bfd2390ed..c834e3a17dbb 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/portable/PortableStatus.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/portable/PortableStatus.java @@ -150,6 +150,10 @@ public class PortableStatus extends SVNStatus { return myInfo; } + public SVNInfo getInfo() { + return initInfo(); + } + @Override public SVNNodeKind getKind() { if (myFileExists) return super.getKind(); diff --git a/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnParseCommandLineParseTest.java b/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnParseCommandLineParseTest.java index 612e63660704..3af195443b4d 100644 --- a/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnParseCommandLineParseTest.java +++ b/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnParseCommandLineParseTest.java @@ -21,6 +21,7 @@ import com.intellij.util.containers.Convertor; import com.intellij.util.containers.MultiMap; import junit.framework.Assert; import junit.framework.TestCase; +import org.jetbrains.idea.svn.commandLine.SvnCommandLineStatusClient; import org.jetbrains.idea.svn.commandLine.SvnInfoHandler; import org.jetbrains.idea.svn.commandLine.SvnStatusHandler; import org.jetbrains.idea.svn.portable.IdeaSVNInfo; @@ -29,8 +30,10 @@ import org.tmatesoft.svn.core.SVNDepth; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNNodeKind; import org.tmatesoft.svn.core.SVNURL; +import org.tmatesoft.svn.core.wc.ISVNStatusHandler; import org.tmatesoft.svn.core.wc.SVNInfo; import org.tmatesoft.svn.core.wc.SVNRevision; +import org.tmatesoft.svn.core.wc.SVNStatus; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; @@ -551,7 +554,8 @@ public class SvnParseCommandLineParseTest extends TestCase { "\n"; final SvnStatusHandler[] handlerArr = new SvnStatusHandler[1]; - final SvnStatusHandler handler = new SvnStatusHandler(new SvnStatusHandler.ExternalDataCallback() { + final SvnStatusHandler handler = new + SvnStatusHandler(new SvnStatusHandler.ExternalDataCallback() { @Override public void switchPath() { handlerArr[0].getPending().getKind(); @@ -574,8 +578,7 @@ public class SvnParseCommandLineParseTest extends TestCase { final int secondIdx = o.getPath().indexOf(":", idx + 1); Assert.assertTrue(o.getPath(), secondIdx == -1); try { - return new IdeaSVNInfo("C:/base/1", SVNURL.parseURIEncoded("http://a.b.c"), SVNRevision.HEAD, SVNNodeKind.FILE, "", - SVNURL.parseURIEncoded("http://a.b.c"), 1, new Date(), "me", null, SVNDepth.EMPTY, 1); + return createStubInfo("C:/base/1", "http://a.b.c"); } catch (SVNException e) { // @@ -589,4 +592,90 @@ public class SvnParseCommandLineParseTest extends TestCase { parser.parse(new ByteArrayInputStream(s.getBytes(CharsetToolkit.UTF8_CHARSET)), handler); final MultiMap changes = handler.getCurrentListChanges(); } + + private IdeaSVNInfo createStubInfo(final String basePath, final String baseUrl) throws SVNException { + return new IdeaSVNInfo(basePath, SVNURL.parseURIEncoded(baseUrl), SVNRevision.HEAD, SVNNodeKind.FILE, "", + SVNURL.parseURIEncoded("http://a.b.c"), 1, new Date(), "me", null, SVNDepth.EMPTY, 1); + } + + public void testStatusInExternalMove() throws Exception { + final String status = "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "admin\n" + + "2012-09-12T12:16:51.621000Z\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "admin\n" + + "2012-09-12T12:16:51.621000Z\n" + + "\n" + + "\n" + + "\n" + + "\n" + + ""; + final String basePath = "C:\\TestProjects\\sortedProjects\\Subversion\\local2\\sep12main\\main"; + final SvnStatusHandler[] handler = new SvnStatusHandler[1]; + final File baseFile = new File(basePath); + final SvnStatusHandler.ExternalDataCallback callback = SvnCommandLineStatusClient.createStatusCallback(new ISVNStatusHandler() { + @Override + public void handleStatus(SVNStatus status) throws SVNException { + System.out.println(status.getURL()); + if (new File("C:\\TestProjects\\sortedProjects\\Subversion\\local2\\sep12main\\main\\slave\\src\\com\\slave\\MacMessagesParser.java").equals(status.getFile())) { + Assert.assertEquals("http://external/src/com/slave/MacMessagesParser.java", status.getURL().toString()); + } + if (new File("C:\\TestProjects\\sortedProjects\\Subversion\\local2\\sep12main\\main\\slave\\src\\com\\slave\\SomeOtherClass.java").equals(status.getFile())) { + Assert.assertEquals("http://external/src/com/slave/SomeOtherClass.java", status.getURL().toString()); + } + } + }, baseFile, createStubInfo(basePath, "http://mainurl/"), handler); + handler[0] = new SvnStatusHandler(callback, baseFile, new Convertor() { + @Override + public SVNInfo convert(File o) { + try { + if (new File("C:\\TestProjects\\sortedProjects\\Subversion\\local2\\sep12main\\main\\slave").equals(o)) { + return createStubInfo(o.getPath(), "http://external"); + } + return createStubInfo(o.getPath(), "http://12345"); + } + catch (SVNException e) { + throw new RuntimeException(e); + } + } + }); + SAXParser parser = SAXParserFactory.newInstance().newSAXParser(); + parser.parse(new ByteArrayInputStream(status.getBytes(CharsetToolkit.UTF8_CHARSET)), handler[0]); + final MultiMap changes = handler[0].getCurrentListChanges(); + } }