mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-94873 Subversion: renamed/moved file located in root added as svn:externals gets incorrect status when command line client is used
when parsing CL status, take into account that there could be externals in the way, and URLs should be calculated with respect to them + test
This commit is contained in:
+108
-58
@@ -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<File, SVNInfo>() {
|
||||
@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<File, SVNInfo>() {
|
||||
@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<File, SVNInfo> externalsMap = new HashMap<File, SVNInfo>();
|
||||
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) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
+92
-3
@@ -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 {
|
||||
"</status>\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<String,PortableStatus> 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 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
|
||||
"<status>\n" +
|
||||
"<target\n" +
|
||||
" path=\".\">\n" +
|
||||
"<entry\n" +
|
||||
" path=\"slave\">\n" +
|
||||
"<wc-status\n" +
|
||||
" item=\"external\"\n" +
|
||||
" props=\"none\">\n" +
|
||||
"</wc-status>\n" +
|
||||
"</entry>\n" +
|
||||
"<entry\n" +
|
||||
" path=\"src\\com\\test\\just\">\n" +
|
||||
"<wc-status\n" +
|
||||
" props=\"none\"\n" +
|
||||
" item=\"unversioned\">\n" +
|
||||
"</wc-status>\n" +
|
||||
"</entry>\n" +
|
||||
"<entry\n" +
|
||||
" path=\"C:\\TestProjects\\sortedProjects\\Subversion\\local2\\sep12main\\main\\slave\\src\\com\\slave\\MacMessagesParser.java\">\n" +
|
||||
"<wc-status\n" +
|
||||
" item=\"added\"\n" +
|
||||
" props=\"none\"\n" +
|
||||
" copied=\"true\">\n" +
|
||||
"<commit\n" +
|
||||
" revision=\"7\">\n" +
|
||||
"<author>admin</author>\n" +
|
||||
"<date>2012-09-12T12:16:51.621000Z</date>\n" +
|
||||
"</commit>\n" +
|
||||
"</wc-status>\n" +
|
||||
"</entry>\n" +
|
||||
"<entry\n" +
|
||||
" path=\"C:\\TestProjects\\sortedProjects\\Subversion\\local2\\sep12main\\main\\slave\\src\\com\\slave\\SomeOtherClass.java\">\n" +
|
||||
"<wc-status\n" +
|
||||
" props=\"none\"\n" +
|
||||
" item=\"deleted\"\n" +
|
||||
" revision=\"7\">\n" +
|
||||
"<commit\n" +
|
||||
" revision=\"7\">\n" +
|
||||
"<author>admin</author>\n" +
|
||||
"<date>2012-09-12T12:16:51.621000Z</date>\n" +
|
||||
"</commit>\n" +
|
||||
"</wc-status>\n" +
|
||||
"</entry>\n" +
|
||||
"</target>\n" +
|
||||
"</status>";
|
||||
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<File, SVNInfo>() {
|
||||
@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<String,PortableStatus> changes = handler[0].getCurrentListChanges();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user