From 4e2db643ffbbffede860f3dbf26195a3d9fbd3c4 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Tue, 4 Feb 2014 14:23:26 +0400 Subject: [PATCH 01/27] IDEA-99123 Fixed "switch" operation for svn 1.7 working copies not to always use SVNKit implementation (now common client factory selection logic is used for update and switch operations) --- .../jetbrains/idea/svn/update/SvnUpdateEnvironment.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/update/SvnUpdateEnvironment.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/update/SvnUpdateEnvironment.java index 0bb436a428ee..d0ad292ece35 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/update/SvnUpdateEnvironment.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/update/SvnUpdateEnvironment.java @@ -96,13 +96,7 @@ public class SvnUpdateEnvironment extends AbstractSvnUpdateIntegrateEnvironment } private UpdateClient createUpdateClient(SvnConfiguration configuration, File root, boolean isSwitch, SVNURL sourceUrl) { - boolean is17 = WorkingCopyFormat.ONE_DOT_SEVEN.equals(myVcs.getWorkingCopyFormat(root)); - boolean isSupportedProtocol = - SvnAuthenticationManager.HTTP.equals(sourceUrl.getProtocol()) || SvnAuthenticationManager.HTTPS.equals(sourceUrl.getProtocol()); - - // TODO: Update this with just myVcs.getFactory(root) when switch and authentication protocols are implemented for command line - ClientFactory factory = is17 && (isSwitch || !isSupportedProtocol) ? myVcs.getSvnKitFactory() : myVcs.getFactory(root); - final UpdateClient updateClient = factory.createUpdateClient(); + final UpdateClient updateClient = myVcs.getFactory(root).createUpdateClient(); if (! isSwitch) { updateClient.setIgnoreExternals(configuration.isIgnoreExternals()); From 20f8ef491b759ec2529661e0d74dd5d7daa66a76 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Tue, 4 Feb 2014 14:50:50 +0400 Subject: [PATCH 02/27] svn: Refactored SvnLogUtil - methods extracted, inlined --- .../idea/svn/history/SvnLogUtil.java | 54 ++++++++++--------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnLogUtil.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnLogUtil.java index db229555c968..54c8e3153e7c 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnLogUtil.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnLogUtil.java @@ -20,6 +20,7 @@ import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList; +import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.SvnBundle; import org.jetbrains.idea.svn.SvnVcs; import org.tmatesoft.svn.core.ISVNLogEntryHandler; @@ -52,33 +53,36 @@ public class SvnLogUtil implements SvnLogLoader { public List loadInterval(final SVNRevision fromIncluding, final SVNRevision toIncluding, final int maxCount, final boolean includingYoungest, final boolean includeOldest) throws SVNException { final List result = new ArrayList(); - loadRevisions(fromIncluding, toIncluding, null, maxCount, result, includingYoungest, includeOldest); + ISVNLogEntryHandler handler = createLogHandler(fromIncluding, toIncluding, includingYoungest, includeOldest, result); + SVNLogClient logger = myVcs.createLogClient(); + + logger + .doLog(myRepositoryRoot, new String[]{myRelative}, SVNRevision.UNDEFINED, fromIncluding, toIncluding, true, true, maxCount, handler); + return result; } - private void loadRevisions(final SVNRevision fromIncluding, final SVNRevision toIncluding, final String author, final int maxCount, - final List result, - final boolean includingYoungest, final boolean includeOldest) throws SVNException { - SVNLogClient logger = myVcs.createLogClient(); - logger.doLog(myRepositoryRoot, new String[]{myRelative}, SVNRevision.UNDEFINED, fromIncluding, toIncluding, true, true, maxCount, - new ISVNLogEntryHandler() { - public void handleLogEntry(SVNLogEntry logEntry) { - if (myProject.isDisposed()) throw new ProcessCanceledException(); - final ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator(); - if (progress != null) { - progress.setText2(SvnBundle.message("progress.text2.processing.revision", logEntry.getRevision())); - progress.checkCanceled(); - } - if ((! includingYoungest) && (logEntry.getRevision() == fromIncluding.getNumber())) { - return; - } - if ((! includeOldest) && (logEntry.getRevision() == toIncluding.getNumber())) { - return; - } - if (author == null || author.equalsIgnoreCase(logEntry.getAuthor())) { - result.add(new SvnChangeList(myVcs, myLocation, logEntry, myRepositoryRoot.toString())); - } - } - }); + @NotNull + private ISVNLogEntryHandler createLogHandler(final SVNRevision fromIncluding, + final SVNRevision toIncluding, + final boolean includingYoungest, + final boolean includeOldest, final List result) { + return new ISVNLogEntryHandler() { + public void handleLogEntry(SVNLogEntry logEntry) { + if (myProject.isDisposed()) throw new ProcessCanceledException(); + final ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator(); + if (progress != null) { + progress.setText2(SvnBundle.message("progress.text2.processing.revision", logEntry.getRevision())); + progress.checkCanceled(); + } + if ((!includingYoungest) && (logEntry.getRevision() == fromIncluding.getNumber())) { + return; + } + if ((!includeOldest) && (logEntry.getRevision() == toIncluding.getNumber())) { + return; + } + result.add(new SvnChangeList(myVcs, myLocation, logEntry, myRepositoryRoot.toString())); + } + }; } } From eee22a351f21fa48aca89799ac6e68ee7aa7b0fd Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Tue, 4 Feb 2014 20:00:04 +0400 Subject: [PATCH 03/27] IDEA-99123 Fixed "Update/Switch to specific revision" dialog not to always use SVNKit implementation --- .../idea/svn/history/BunchFactory.java | 6 ++--- .../idea/svn/history/BunchProvider.java | 4 +-- .../idea/svn/history/CachedProvider.java | 4 +-- .../idea/svn/history/LiveProvider.java | 25 +++++++++++-------- .../idea/svn/history/SvnLogLoader.java | 5 ++-- .../idea/svn/history/SvnLogUtil.java | 16 +++++------- .../svn/history/SvnRepositoryLocation.java | 13 ++++++++++ .../SvnRevisionsNavigationMediator.java | 9 ++----- .../idea/svn/SvnCachingRevisionsTest.java | 5 ++-- .../idea/svn16/SvnCachingRevisionsTest.java | 5 ++-- 10 files changed, 52 insertions(+), 40 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/BunchFactory.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/BunchFactory.java index 1e4760b487a4..426c760836b6 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/BunchFactory.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/BunchFactory.java @@ -17,8 +17,8 @@ package org.jetbrains.idea.svn.history; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.util.Ref; +import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList; -import org.tmatesoft.svn.core.SVNException; import java.util.ArrayList; import java.util.Iterator; @@ -57,7 +57,7 @@ public class BunchFactory { myYoungest = -1; } - public List goBack(final int bunchSize, final Ref myYoungestRead) throws SVNException { + public List goBack(final int bunchSize, final Ref myYoungestRead) throws VcsException { execute(bunchSize); myYoungestRead.set(myLiveProvider.isEarliestRevisionWasAccessed()); return new ArrayList(myResult); @@ -78,7 +78,7 @@ public class BunchFactory { myYoungest = subList.get(subList.size() - 1).getNumber(); } - private void execute(final int bunchSize) throws SVNException { + private void execute(final int bunchSize) throws VcsException { myBunchSize = bunchSize; myResult.clear(); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/BunchProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/BunchProvider.java index 482cce94d97f..60944744a00e 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/BunchProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/BunchProvider.java @@ -15,8 +15,8 @@ */ package org.jetbrains.idea.svn.history; +import com.intellij.openapi.vcs.VcsException; import org.jetbrains.annotations.Nullable; -import org.tmatesoft.svn.core.SVNException; public interface BunchProvider { long getEarliestRevision(); @@ -29,6 +29,6 @@ public interface BunchProvider { */ @Nullable Fragment getEarliestBunchInInterval(final long earliestRevision, final long oldestRevision, final int desirableSize, - final boolean includeYoungest, final boolean includeOldest) throws SVNException; + final boolean includeYoungest, final boolean includeOldest) throws VcsException; boolean isEmpty(); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/CachedProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/CachedProvider.java index 294a2cd29a30..b261ff190e49 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/CachedProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/CachedProvider.java @@ -15,10 +15,10 @@ */ package org.jetbrains.idea.svn.history; +import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.changes.committed.ChangesBunch; import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList; import org.jetbrains.annotations.Nullable; -import org.tmatesoft.svn.core.SVNException; import java.util.ArrayList; import java.util.Iterator; @@ -86,7 +86,7 @@ public abstract class CachedProvider implements BunchProvider { @Nullable public Fragment getEarliestBunchInInterval(final long earliestRevision, final long oldestRevision, final int desirableSize, - final boolean includeYoungest, final boolean includeOldest) throws SVNException { + final boolean includeYoungest, final boolean includeOldest) throws VcsException { if ((earliestRevision > getEarliestRevision()) || (earliestRevision == -1)) { if (myAlreadyReaded == null) { return null; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/LiveProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/LiveProvider.java index 573a22647fdb..b50a6de8d970 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/LiveProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/LiveProvider.java @@ -20,12 +20,13 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.util.Ref; +import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList; +import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.SvnBundle; import org.jetbrains.idea.svn.SvnVcs; +import org.jetbrains.idea.svn.commandLine.SvnBindException; import org.tmatesoft.svn.core.SVNErrorCode; -import org.tmatesoft.svn.core.SVNException; -import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.wc.SVNRevision; import java.util.Iterator; @@ -54,7 +55,7 @@ public class LiveProvider implements BunchProvider { } public Fragment getEarliestBunchInInterval(final long earliestRevision, final long oldestRevision, final int desirableSize, - final boolean includeYoungest, final boolean includeOldest) throws SVNException { + final boolean includeYoungest, final boolean includeOldest) throws VcsException { return getEarliestBunchInIntervalImpl(earliestRevision, oldestRevision, desirableSize, includeYoungest, includeOldest, earliestRevision); } @@ -62,14 +63,14 @@ public class LiveProvider implements BunchProvider { final long oldestRevision, final int desirableSize, final boolean includeYoungest, - final boolean includeOldest, final long earliestToTake) throws SVNException { + final boolean includeOldest, final long earliestToTake) throws VcsException { if ((myEarliestRevisionWasAccessed) || ((oldestRevision == myYoungestRevision) && ((! includeYoungest) || (! includeOldest)))) { return null; } final SVNRevision youngRevision = (earliestRevision == -1) ? SVNRevision.HEAD : SVNRevision.create(earliestRevision); final Ref> refToList = new Ref>(); - final Ref exceptionRef = new Ref(); + final Ref exceptionRef = new Ref(); final Runnable loader = new Runnable() { public void run() { @@ -77,7 +78,7 @@ public class LiveProvider implements BunchProvider { refToList.set( myLoader.loadInterval(youngRevision, SVNRevision.create(oldestRevision), desirableSize, includeYoungest, includeOldest)); } - catch (SVNException e) { + catch (VcsException e) { exceptionRef.set(e); } } @@ -98,13 +99,13 @@ public class LiveProvider implements BunchProvider { }, SvnBundle.message("progress.live.provider.loading.revisions.text"), false, myVcs.getProject()); } - if (exceptionRef.get() != null) { - final SVNException e = exceptionRef.get(); - if (SVNErrorCode.FS_NOT_FOUND.equals(e.getErrorMessage().getErrorCode())) { + if (!exceptionRef.isNull()) { + final VcsException e = exceptionRef.get(); + if (isElementNotFound(e)) { // occurs when target URL is deleted in repository // try to find latest existent revision. expensive ... final LatestExistentSearcher searcher = new LatestExistentSearcher(oldestRevision, myYoungestRevision, (oldestRevision != 0), - myVcs, SVNURL.parseURIEncoded(myLocation.getURL())); + myVcs, myLocation.toSvnUrl()); final long existent = searcher.getLatestExistent(); if ((existent == -1) || (existent == earliestRevision)) { myEarliestRevisionWasAccessed = true; @@ -132,6 +133,10 @@ public class LiveProvider implements BunchProvider { return new Fragment(Origin.LIVE, list, true, true, null); } + private static boolean isElementNotFound(@NotNull VcsException e) { + return e instanceof SvnBindException && ((SvnBindException)e).contains(SVNErrorCode.FS_NOT_FOUND); + } + public boolean isEarliestRevisionWasAccessed() { return myEarliestRevisionWasAccessed; } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnLogLoader.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnLogLoader.java index 4ed82c6ed78b..0ff2e3b34e46 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnLogLoader.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnLogLoader.java @@ -15,13 +15,14 @@ */ package org.jetbrains.idea.svn.history; +import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList; -import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.wc.SVNRevision; import java.util.List; public interface SvnLogLoader { List loadInterval(final SVNRevision fromIncluding, final SVNRevision toIncluding, - final int maxCount, final boolean includingYoungest, final boolean includeOldest) throws SVNException; + final int maxCount, final boolean includingYoungest, final boolean includeOldest) + throws VcsException; } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnLogUtil.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnLogUtil.java index 54c8e3153e7c..7f4f25f023a9 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnLogUtil.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnLogUtil.java @@ -19,16 +19,16 @@ import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList; import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.SvnBundle; import org.jetbrains.idea.svn.SvnVcs; import org.tmatesoft.svn.core.ISVNLogEntryHandler; -import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNLogEntry; import org.tmatesoft.svn.core.SVNURL; -import org.tmatesoft.svn.core.wc.SVNLogClient; import org.tmatesoft.svn.core.wc.SVNRevision; +import org.tmatesoft.svn.core.wc2.SvnTarget; import java.util.ArrayList; import java.util.List; @@ -38,26 +38,22 @@ public class SvnLogUtil implements SvnLogLoader { private final SvnVcs myVcs; private final SvnRepositoryLocation myLocation; private final SVNURL myRepositoryRoot; - private final String myRelative; public SvnLogUtil(final Project project, final SvnVcs vcs, final SvnRepositoryLocation location, final SVNURL repositoryRoot) { myProject = project; myVcs = vcs; myLocation = location; myRepositoryRoot = repositoryRoot; - - final String repositoryRootPath = repositoryRoot.toString(); - myRelative = myLocation.getURL().substring(repositoryRootPath.length()); } public List loadInterval(final SVNRevision fromIncluding, final SVNRevision toIncluding, - final int maxCount, final boolean includingYoungest, final boolean includeOldest) throws SVNException { + final int maxCount, final boolean includingYoungest, final boolean includeOldest) + throws VcsException { final List result = new ArrayList(); ISVNLogEntryHandler handler = createLogHandler(fromIncluding, toIncluding, includingYoungest, includeOldest, result); - SVNLogClient logger = myVcs.createLogClient(); + SvnTarget target = SvnTarget.fromURL(myLocation.toSvnUrl()); - logger - .doLog(myRepositoryRoot, new String[]{myRelative}, SVNRevision.UNDEFINED, fromIncluding, toIncluding, true, true, maxCount, handler); + myVcs.getFactory(target).createHistoryClient().doLog(target, fromIncluding, toIncluding, true, true, false, maxCount, null, handler); return result; } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnRepositoryLocation.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnRepositoryLocation.java index 3d5bcaf0d92b..7290f0030032 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnRepositoryLocation.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnRepositoryLocation.java @@ -21,7 +21,11 @@ import com.intellij.openapi.vcs.VcsException; import com.intellij.util.NotNullFunction; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.RootUrlInfo; +import org.jetbrains.idea.svn.SvnUtil; import org.jetbrains.idea.svn.SvnVcs; +import org.jetbrains.idea.svn.commandLine.SvnBindException; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.SVNURL; import java.io.File; @@ -69,4 +73,13 @@ public class SvnRepositoryLocation implements RepositoryLocation { return null; } + + public SVNURL toSvnUrl() throws VcsException { + try { + return SvnUtil.createUrl(myURL); + } + catch (SVNException e) { + throw new SvnBindException(e); + } + } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnRevisionsNavigationMediator.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnRevisionsNavigationMediator.java index 26e5152b2d7f..5857623d4955 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnRevisionsNavigationMediator.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnRevisionsNavigationMediator.java @@ -64,6 +64,7 @@ public class SvnRevisionsNavigationMediator implements CommittedChangesNavigatio public void run() { SVNRepository repository = null; try { + // TODO: Rewrite this using "svn info -r HEAD" repository = vcs.createRepository(location.getURL()); youngRevision[0] = repository.getLatestRevision(); repositoryRoot[0] = repository.getRepositoryRoot(false); @@ -133,13 +134,7 @@ public class SvnRevisionsNavigationMediator implements CommittedChangesNavigatio } final Ref canNotGoBackRef = new Ref(); - final List fragments; - try { - fragments = myChunkFactory.goBack(CHUNK_SIZE, canNotGoBackRef); - } - catch (SVNException e) { - throw new VcsException(e); - } + final List fragments = myChunkFactory.goBack(CHUNK_SIZE, canNotGoBackRef); myCanNotGoBack = canNotGoBackRef.get().booleanValue(); if (! fragments.isEmpty()) { diff --git a/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnCachingRevisionsTest.java b/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnCachingRevisionsTest.java index ef809649cca6..1f0f7f868780 100644 --- a/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnCachingRevisionsTest.java +++ b/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnCachingRevisionsTest.java @@ -3,11 +3,11 @@ package org.jetbrains.idea.svn; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.changes.committed.ChangesBunch; import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList; import com.intellij.testFramework.fixtures.CodeInsightFixtureTestCase; import org.jetbrains.idea.svn.history.*; -import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNLogEntry; import org.tmatesoft.svn.core.wc.SVNRevision; @@ -48,7 +48,8 @@ public class SvnCachingRevisionsTest extends CodeInsightFixtureTestCase { @Override public List loadInterval(final SVNRevision fromIncluding, final SVNRevision toIncluding, final int maxCount, - final boolean includingYoungest, final boolean includeOldest) throws SVNException { + final boolean includingYoungest, final boolean includeOldest) + throws VcsException { long young = fromIncluding.getNumber(); young = (young == -1) ? myRevisions.get(myRevisions.size() - 1) : young; final long old = toIncluding.getNumber(); diff --git a/plugins/svn4idea/testSource/org/jetbrains/idea/svn16/SvnCachingRevisionsTest.java b/plugins/svn4idea/testSource/org/jetbrains/idea/svn16/SvnCachingRevisionsTest.java index b06502866c81..dca29f03646f 100644 --- a/plugins/svn4idea/testSource/org/jetbrains/idea/svn16/SvnCachingRevisionsTest.java +++ b/plugins/svn4idea/testSource/org/jetbrains/idea/svn16/SvnCachingRevisionsTest.java @@ -3,12 +3,12 @@ package org.jetbrains.idea.svn16; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.changes.committed.ChangesBunch; import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList; import com.intellij.testFramework.fixtures.CodeInsightFixtureTestCase; import org.jetbrains.idea.svn.SvnApplicationSettings; import org.jetbrains.idea.svn.history.*; -import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNLogEntry; import org.tmatesoft.svn.core.wc.SVNRevision; @@ -49,7 +49,8 @@ public class SvnCachingRevisionsTest extends CodeInsightFixtureTestCase { @Override public List loadInterval(final SVNRevision fromIncluding, final SVNRevision toIncluding, final int maxCount, - final boolean includingYoungest, final boolean includeOldest) throws SVNException { + final boolean includingYoungest, final boolean includeOldest) + throws VcsException { long young = fromIncluding.getNumber(); young = (young == -1) ? myRevisions.get(myRevisions.size() - 1) : young; final long old = toIncluding.getNumber(); From 329845baeb67d2b61f7516eeb738f759b9659009 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Tue, 4 Feb 2014 20:47:50 +0400 Subject: [PATCH 04/27] IDEA-99123 Fixed latest revision detection logic for "Update/Switch to specific revision" dialog to use "svn info" command (instead of SVNRepository api from SVNKit) --- .../SvnRevisionsNavigationMediator.java | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnRevisionsNavigationMediator.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnRevisionsNavigationMediator.java index 5857623d4955..8f29e01a8403 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnRevisionsNavigationMediator.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnRevisionsNavigationMediator.java @@ -29,8 +29,8 @@ import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.idea.svn.SvnVcs; import org.tmatesoft.svn.core.SVNException; -import org.tmatesoft.svn.core.SVNURL; -import org.tmatesoft.svn.core.io.SVNRepository; +import org.tmatesoft.svn.core.wc.SVNInfo; +import org.tmatesoft.svn.core.wc.SVNRevision; import java.util.*; @@ -55,32 +55,30 @@ public class SvnRevisionsNavigationMediator implements CommittedChangesNavigatio myChunks = new LinkedList>(); - final SVNURL[] repositoryRoot = new SVNURL[1]; - final long[] youngRevision = new long[1]; final VcsException[] exception = new VcsException[1]; + final Ref infoRef = new Ref(); Runnable process = new Runnable() { @Override public void run() { - SVNRepository repository = null; try { - // TODO: Rewrite this using "svn info -r HEAD" - repository = vcs.createRepository(location.getURL()); - youngRevision[0] = repository.getLatestRevision(); - repositoryRoot[0] = repository.getRepositoryRoot(false); + infoRef.set(vcs.getInfo(location.toSvnUrl(), SVNRevision.HEAD)); + } + catch (VcsException e) { + exception[0] = e; } catch (SVNException e) { exception[0] = new VcsException(e); } - finally { - if (repository != null) { - repository.closeSession(); - } - } } }; underProgress(exception, process); + SVNInfo info = infoRef.get(); + if (info == null || info.getRevision() == null || info.getRepositoryRootURL() == null) { + throw new VcsException("Could not get head info for " + location); + } + final Iterator visualIterator = project.isDefault() ? null : CommittedChangesCache.getInstance(project).getBackBunchedIterator(vcs, vcsRoot, location, CHUNK_SIZE); final Iterator internalIterator = project.isDefault() ? null : LoadedRevisionsCache.getInstance(project).iterator(location.getURL()); @@ -88,8 +86,9 @@ public class SvnRevisionsNavigationMediator implements CommittedChangesNavigatio myInternallyCached = (internalIterator == null) ? null : new InternallyCachedProvider(internalIterator, myProject); myVisuallyCached = (visualIterator == null) ? null : new VisuallyCachedProvider(visualIterator, myProject, location); - myChunkFactory = new BunchFactory(myInternallyCached, myVisuallyCached, - new LiveProvider(vcs, location, youngRevision[0], new SvnLogUtil(myProject, vcs, location, repositoryRoot[0]))); + myChunkFactory = new BunchFactory(myInternallyCached, myVisuallyCached, new LiveProvider(vcs, location, info.getRevision().getNumber(), + new SvnLogUtil(myProject, vcs, location, + info.getRepositoryRootURL()))); myCurrentIdx = -1; From d72179f10c5118f1611e8835d9e121cc2bc1239e Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Wed, 5 Feb 2014 14:41:47 +0400 Subject: [PATCH 05/27] svn: Refactored TreeConflictRefreshablePanel - commented code removed, simplifications --- .../TreeConflictRefreshablePanel.java | 44 ++----------------- 1 file changed, 3 insertions(+), 41 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/treeConflict/TreeConflictRefreshablePanel.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/treeConflict/TreeConflictRefreshablePanel.java index 57a7e219263b..da0b1e7f590b 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/treeConflict/TreeConflictRefreshablePanel.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/treeConflict/TreeConflictRefreshablePanel.java @@ -193,12 +193,6 @@ public class TreeConflictRefreshablePanel extends AbstractRefreshablePanel { return EmptyConflictSide.getInstance(); } } - // todo temporally - /*if (SVNNodeKind.DIR.equals(version.getKind())) { - return new HistoryAsBrowseChangesConflictSide(myVcs.getProject(), version); - } else { - return new HistoryConflictSide(myVcs, version); - }*/ HistoryConflictSide side = new HistoryConflictSide(myVcs, version, untilThisOther); if (untilThisOther != null && ! isLeft) { side.setListToReportLoaded(myRightRevisionsList); @@ -314,11 +308,7 @@ public class TreeConflictRefreshablePanel extends AbstractRefreshablePanel { additionalPath = myChange.getAfterRevision().getFile(); } } else { - if (myChange.getBeforeRevision() != null) { - mainPath = myChange.getBeforeRevision().getFile(); - } else { - mainPath = myChange.getAfterRevision().getFile(); - } + mainPath = myChange.getBeforeRevision() != null ? myChange.getBeforeRevision().getFile() : myChange.getAfterRevision().getFile(); } return new Paths(mainPath, additionalPath); } @@ -368,15 +358,6 @@ public class TreeConflictRefreshablePanel extends AbstractRefreshablePanel { return null; } // my edit, theirs move or delete - /*if (SVNConflictAction.DELETE.equals(description.getConflictAction()) && description.getSourceLeftVersion() != null) { - //todo - return new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - mergeMyEditTheirsDelete(); - } - }; - } */ if (SVNConflictAction.EDIT.equals(description.getConflictAction()) && description.getSourceLeftVersion() != null && SVNConflictReason.DELETED.equals(description.getConflictReason()) && (myChange.isMoved() || myChange.isRenamed()) && myCommittedRevision != null) { @@ -397,10 +378,7 @@ public class TreeConflictRefreshablePanel extends AbstractRefreshablePanel { } public static String filePath(FilePath newFilePath) { - return newFilePath.getName() + - " (" + - newFilePath.getParentPath().getPath() + - ")"; + return newFilePath.getName() + " (" + newFilePath.getParentPath().getPath() + ")"; } private static ActionListener createBoth(SVNTreeConflictDescription description) { @@ -524,12 +502,7 @@ public class TreeConflictRefreshablePanel extends AbstractRefreshablePanel { @Override public void load() throws SVNException, VcsException { SVNRevision from = SVNRevision.create(myVersion.getPegRevision()); - if (myPeg == null) { - // just a portion of history - myProvider.reportAppendableHistory(myPath, mySessionAdapter, from, myPeg, LIMIT, myPeg, true); - } else { - myProvider.reportAppendableHistory(myPath, mySessionAdapter, from, myPeg, 0, myPeg, true); - } + myProvider.reportAppendableHistory(myPath, mySessionAdapter, from, myPeg, myPeg == null ? LIMIT : 0, myPeg, true); VcsAbstractHistorySession session = mySessionAdapter.getSession(); if (myListToReportLoaded != null && session != null) { List list = session.getRevisionList(); @@ -576,15 +549,4 @@ public class TreeConflictRefreshablePanel extends AbstractRefreshablePanel { return myFileHistoryPanel; } } - - /*private static class HistoryAsBrowseChangesConflictSide implements AbstractConflictSide { - public HistoryAsBrowseChangesConflictSide(Project project, SVNConflictVersion version) { - //To change body of created methods use File | Settings | File Templates. - } - - @Override - public JPanel createPanel() { - return null; - } - }*/ } From cf4631198bb77ca38808b37c95d1dc6bbc6b9a7a Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Wed, 5 Feb 2014 14:51:40 +0400 Subject: [PATCH 06/27] svn: Fixed revisions loading in tree conflict panel for tree conflicts with "incoming delete" --- .../src/org/jetbrains/idea/svn/SvnUtil.java | 1 + .../idea/svn/history/SvnHistoryProvider.java | 15 +++++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java index 490d8905a7e7..6a86c7ac2e89 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java @@ -569,6 +569,7 @@ public class SvnUtil { return repository.hasCapability(SVNCapability.MERGE_INFO); } catch (SVNException e) { + // TODO: Exception is thrown when url just not exist (was deleted, for instance) => and false is returned which seems not to be correct. return false; } finally { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java index b5dfd8ccdbd4..1fdc0c5879e3 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java @@ -409,12 +409,15 @@ public class SvnHistoryProvider } private void loadBackwards(SVNURL svnurl) throws SVNException, VcsException { - final SVNURL rootURL = getRepositoryRoot(svnurl, myFrom); - final String root = rootURL.toString(); - String relativeUrl = myUrl; - if (myUrl.startsWith(root)) { - relativeUrl = myUrl.substring(root.length()); - } + // this method is called when svnurl does not exist in latest repository revision - thus concrete old revision is used for "info" + // command to get repository url + SVNInfo info = myVcs.getInfo(svnurl, myPeg, myPeg); + final SVNURL rootURL = info != null ? info.getRepositoryRootURL() : null; + final String root = rootURL != null ? rootURL.toString() : ""; + String relativeUrl = myUrl; + if (myUrl.startsWith(root)) { + relativeUrl = myUrl.substring(root.length()); + } // TODO: Update this call to myVcs.getFactory.createHistoryClient SVNLogClient client = myVcs.createLogClient(); From 6f42f9cf4782625d5422be261cc8d3df08b4e3cb Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Wed, 5 Feb 2014 15:51:53 +0400 Subject: [PATCH 07/27] svn: Explicitly specify "limit=1" when retrieving history for tree conflict panel (instead of throwing cancel exception) --- .../org/jetbrains/idea/svn/history/SvnHistoryProvider.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java index 1fdc0c5879e3..cab597ce38a4 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java @@ -428,12 +428,12 @@ public class SvnHistoryProvider @Override public void consume(VcsFileRevision revision) throws SVNException { myConsumer.consume(revision); - throw new SVNCancelException(); // load only one revision } }, rootURL); repositoryLogEntryHandler.setThrowCancelOnMeetPathCreation(true); - client.doLog(rootURL, new String[]{}, myFrom, myFrom, myTo == null ? SVNRevision.create(1) : myTo, false, true, myShowMergeSources && mySupport15, 0, null, repositoryLogEntryHandler); + client.doLog(rootURL, new String[]{}, myFrom, myFrom, myTo == null ? SVNRevision.create(1) : myTo, false, true, + myShowMergeSources && mySupport15, 1, null, repositoryLogEntryHandler); } // TODO: try to rewrite without separately retrieving repository url by item url - as this command could require authentication From d1e99e223e3b178841adca4f07b41df166cca7d4 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Wed, 5 Feb 2014 16:04:22 +0400 Subject: [PATCH 08/27] svn: Fixed revisions loading in tree conflict panel for tree conflicts with "incoming delete" to use common ClientFactory model --- .../idea/svn/history/SvnHistoryProvider.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java index cab597ce38a4..8f9b66dbfdf1 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java @@ -44,7 +44,6 @@ import org.tmatesoft.svn.core.*; import org.tmatesoft.svn.core.internal.util.SVNPathUtil; import org.tmatesoft.svn.core.internal.wc.SVNErrorManager; import org.tmatesoft.svn.core.wc.SVNInfo; -import org.tmatesoft.svn.core.wc.SVNLogClient; import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc2.SvnTarget; import org.tmatesoft.svn.util.SVNLogType; @@ -419,10 +418,7 @@ public class SvnHistoryProvider relativeUrl = myUrl.substring(root.length()); } - // TODO: Update this call to myVcs.getFactory.createHistoryClient - SVNLogClient client = myVcs.createLogClient(); - - final RepositoryLogEntryHandler repositoryLogEntryHandler = + final RepositoryLogEntryHandler repositoryLogEntryHandler = new RepositoryLogEntryHandler(myVcs, myUrl, SVNRevision.UNDEFINED, relativeUrl, new ThrowableConsumer() { @Override @@ -430,10 +426,12 @@ public class SvnHistoryProvider myConsumer.consume(revision); } }, rootURL); - repositoryLogEntryHandler.setThrowCancelOnMeetPathCreation(true); + repositoryLogEntryHandler.setThrowCancelOnMeetPathCreation(true); - client.doLog(rootURL, new String[]{}, myFrom, myFrom, myTo == null ? SVNRevision.create(1) : myTo, false, true, - myShowMergeSources && mySupport15, 1, null, repositoryLogEntryHandler); + SvnTarget target = SvnTarget.fromURL(rootURL, myFrom); + myVcs.getFactory(target).createHistoryClient() + .doLog(target, myFrom, myTo == null ? SVNRevision.create(1) : myTo, false, true, myShowMergeSources && mySupport15, 1, null, + repositoryLogEntryHandler); } // TODO: try to rewrite without separately retrieving repository url by item url - as this command could require authentication From e3bd2bb542b50d3be75c97a593df2fe345d67935 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Wed, 5 Feb 2014 16:34:18 +0400 Subject: [PATCH 09/27] svn: Refactored RepositoryBrowserDialog - code simplifications --- .../idea/svn/dialogs/RepositoryBrowserDialog.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryBrowserDialog.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryBrowserDialog.java index 32a73ac8d0e5..ae9fd514de79 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryBrowserDialog.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryBrowserDialog.java @@ -35,7 +35,6 @@ import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.vcs.*; -import com.intellij.openapi.vcs.actions.VcsContextFactory; import com.intellij.openapi.vcs.changes.Change; import com.intellij.openapi.vcs.changes.ChangesUtil; import com.intellij.openapi.vcs.changes.ContentRevision; @@ -47,6 +46,7 @@ import com.intellij.ui.PopupHandler; import com.intellij.util.IconUtil; import com.intellij.util.NotNullFunction; import com.intellij.util.WaitForProgressToShow; +import com.intellij.vcsUtil.VcsUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -57,7 +57,6 @@ import org.jetbrains.idea.svn.dialogs.browser.*; import org.jetbrains.idea.svn.dialogs.browserCache.Expander; import org.jetbrains.idea.svn.dialogs.browserCache.KeepingExpandedExpander; import org.jetbrains.idea.svn.dialogs.browserCache.SyntheticWorker; -import org.jetbrains.idea.svn.history.SvnHistoryProvider; import org.jetbrains.idea.svn.history.SvnRepositoryLocation; import org.jetbrains.idea.svn.status.SvnDiffEditor; import org.tmatesoft.svn.core.*; @@ -355,9 +354,10 @@ public class RepositoryBrowserDialog extends DialogWrapper { } boolean isDirectory = node.getUserObject() instanceof SVNURL || (node.getSVNDirEntry() != null && node.getSVNDirEntry().getKind() == SVNNodeKind.DIR); - AbstractVcsHelper.getInstance(myProject).showFileHistory(new SvnHistoryProvider(myVCS), - VcsContextFactory.SERVICE.getInstance().createFilePathOnNonLocal(node.getURL().toDecodedString(), isDirectory), - myVCS, node.getURL().toDecodedString()); + String url = node.getURL().toDecodedString(); + + AbstractVcsHelper.getInstance(myProject) + .showFileHistory(myVCS.getVcsHistoryProvider(), VcsUtil.getFilePathOnNonLocal(url, isDirectory), myVCS, url); node.reload(false); } } From d1106d7687caec651219bb6ae4a19f26ca8863ec Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Wed, 5 Feb 2014 16:47:35 +0400 Subject: [PATCH 10/27] svn: Refactored SvnHistoryProvider - reuse repository root detection logic from SvnUtil --- .../idea/svn/history/SvnHistoryProvider.java | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java index 8f9b66dbfdf1..90fc3bf8c2da 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java @@ -379,7 +379,10 @@ public class SvnHistoryProvider final SVNURL svnurl = SVNURL.parseURIEncoded(myUrl); SVNRevision operationalFrom = myFrom == null ? SVNRevision.HEAD : myFrom; - final SVNURL rootURL = getRepositoryRoot(svnurl, myFrom); + // TODO: try to rewrite without separately retrieving repository url by item url - as this command could require authentication + // TODO: and it is not "clear enough/easy to implement" with current design (for some cases) how to cache credentials (if in + // TODO: non-interactive mode) + final SVNURL rootURL = SvnUtil.getRepositoryRoot(myVcs, svnurl); if (rootURL == null) { throw new VcsException("Could not find repository root for URL: " + myUrl); } @@ -434,15 +437,6 @@ public class SvnHistoryProvider repositoryLogEntryHandler); } - // TODO: try to rewrite without separately retrieving repository url by item url - as this command could require authentication - // TODO: and it is not "clear enough/easy to implement" with current design (for some cases) how to cache credentials (if in - // TODO: non-interactive mode) - private SVNURL getRepositoryRoot(SVNURL svnurl, SVNRevision operationalFrom) throws SVNException { - SVNInfo info = myVcs.getInfo(svnurl, SVNRevision.HEAD); - - return info != null ? info.getRepositoryRootURL() : null; - } - private boolean existsNow(SVNURL svnurl) { final SVNInfo info; try { From 3695846f0569335111ca3c8722864d09c056a9ce Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Wed, 5 Feb 2014 17:01:56 +0400 Subject: [PATCH 11/27] svn: Refactored SvnCommittedChangesProvider - removed duplication in repository root detection logic --- .../history/SvnCommittedChangesProvider.java | 66 +++++++------------ 1 file changed, 22 insertions(+), 44 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java index a8d76b11dc56..7e03ba527cfd 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java @@ -184,21 +184,7 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi progress.setText2(SvnBundle.message("progress.text2.changes.establishing.connection", location)); } - // TODO: Implement this with command line - final String repositoryRoot; - SVNRepository repository = null; - try { - repository = myVcs.createRepository(svnLocation.getURL()); - repositoryRoot = repository.getRepositoryRoot(true).toString(); - } - catch (SVNException e) { - throw new VcsException(e); - } finally { - if (repository != null) { - repository.closeSession(); - } - } - + final String repositoryRoot = getRepositoryRoot(svnLocation); final ChangeBrowserSettings.Filter filter = settings.createFilter(); getCommittedChangesImpl(settings, svnLocation.getURL(), new String[]{""}, maxCount, new Consumer() { @@ -224,21 +210,7 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi progress.setText2(SvnBundle.message("progress.text2.changes.establishing.connection", location)); } - final String repositoryRoot; - // TODO: Implement this with command line - SVNRepository repository = null; - try { - repository = myVcs.createRepository(svnLocation.getURL()); - repositoryRoot = repository.getRepositoryRoot(true).toString(); - repository.closeSession(); - } - catch (SVNException e) { - throw new VcsException(e); - } finally { - if (repository != null) { - repository.closeSession(); - } - } + final String repositoryRoot = getRepositoryRoot(svnLocation); getCommittedChangesImpl(settings, svnLocation.getURL(), new String[]{""}, maxCount, new Consumer() { public void consume(final SVNLogEntry svnLogEntry) { @@ -259,20 +231,7 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi progress.setText(SvnBundle.message("progress.text.changes.collecting.changes")); progress.setText2(SvnBundle.message("progress.text2.changes.establishing.connection", location)); } - // TODO: Rewrite this without using SVNKit - final String repositoryRoot; - SVNRepository repository = null; - try { - repository = myVcs.createRepository(svnLocation.getURL()); - repositoryRoot = repository.getRepositoryRoot(true).toString(); - } - catch (SVNException e) { - throw new VcsException(e); - } finally { - if (repository != null) { - repository.closeSession(); - } - } + final String repositoryRoot = getRepositoryRoot(svnLocation); final MergeTrackerProxy proxy = new MergeTrackerProxy(new Consumer>() { public void consume(TreeStructureNode node) { @@ -300,6 +259,25 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi proxy.finish(); } + private String getRepositoryRoot(@NotNull SvnRepositoryLocation svnLocation) throws VcsException { + // TODO: Implement this with command line + + final String repositoryRoot; + SVNRepository repository = null; + + try { + repository = myVcs.createRepository(svnLocation.getURL()); + repositoryRoot = repository.getRepositoryRoot(true).toString(); + } + catch (SVNException e) { + throw new VcsException(e); + } finally { + if (repository != null) { + repository.closeSession(); + } + } + return repositoryRoot; + } private static class MergeTrackerProxy implements ThrowableConsumer, SVNException> { private TreeStructureNode myCurrentHierarchy; From 90e4f2918d5fa0714ec286856ab30976dbb3545b Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Wed, 5 Feb 2014 20:15:10 +0400 Subject: [PATCH 12/27] svn: Refactored SvnCommittedChangesProvider - simplified progress indicator updating --- .../history/SvnCommittedChangesProvider.java | 39 +++++-------------- 1 file changed, 10 insertions(+), 29 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java index 7e03ba527cfd..efcd14cdeb7f 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java @@ -20,7 +20,6 @@ import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProcessCanceledException; -import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; @@ -110,7 +109,6 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi @Nullable public RepositoryLocation getLocationFor(final FilePath root) { - final ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator(); final String url = SvnUtil.getExactLocation(myVcs, root.getIOFile()); return url == null ? null : new SvnRepositoryLocation(url); } @@ -178,12 +176,6 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi throws VcsException { try { final SvnRepositoryLocation svnLocation = (SvnRepositoryLocation) location; - final ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator(); - if (progress != null) { - progress.setText(SvnBundle.message("progress.text.changes.collecting.changes")); - progress.setText2(SvnBundle.message("progress.text2.changes.establishing.connection", location)); - } - final String repositoryRoot = getRepositoryRoot(svnLocation); final ChangeBrowserSettings.Filter filter = settings.createFilter(); @@ -204,12 +196,6 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi public List getCommittedChanges(ChangeBrowserSettings settings, final RepositoryLocation location, final int maxCount) throws VcsException { final SvnRepositoryLocation svnLocation = (SvnRepositoryLocation) location; final ArrayList result = new ArrayList(); - final ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator(); - if (progress != null) { - progress.setText(SvnBundle.message("progress.text.changes.collecting.changes")); - progress.setText2(SvnBundle.message("progress.text2.changes.establishing.connection", location)); - } - final String repositoryRoot = getRepositoryRoot(svnLocation); getCommittedChangesImpl(settings, svnLocation.getURL(), new String[]{""}, maxCount, new Consumer() { @@ -226,11 +212,6 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi final PairConsumer> finalConsumer) throws VcsException { final SvnRepositoryLocation svnLocation = (SvnRepositoryLocation) location; - final ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator(); - if (progress != null) { - progress.setText(SvnBundle.message("progress.text.changes.collecting.changes")); - progress.setText2(SvnBundle.message("progress.text2.changes.establishing.connection", location)); - } final String repositoryRoot = getRepositoryRoot(svnLocation); final MergeTrackerProxy proxy = new MergeTrackerProxy(new Consumer>() { @@ -255,7 +236,7 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi } } }, true, false); - + proxy.finish(); } @@ -328,11 +309,8 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi private void getCommittedChangesImpl(ChangeBrowserSettings settings, final String url, final String[] filterUrls, final int maxCount, final Consumer resultConsumer, final boolean includeMergedRevisions, final boolean filterOutByDate) throws VcsException { - final ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator(); - if (progress != null) { - progress.setText(SvnBundle.message("progress.text.changes.collecting.changes")); - progress.setText2(SvnBundle.message("progress.text2.changes.establishing.connection", url)); - } + setCollectingChangesProgress(url); + try { SVNLogClient logger = myVcs.createLogClient(); @@ -380,10 +358,8 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi new ISVNLogEntryHandler() { public void handleLogEntry(SVNLogEntry logEntry) { if (myProject.isDisposed()) throw new ProcessCanceledException(); - if (progress != null) { - progress.setText2(SvnBundle.message("progress.text2.processing.revision", logEntry.getRevision())); - progress.checkCanceled(); - } + + ProgressManager.progress2(SvnBundle.message("progress.text2.processing.revision", logEntry.getRevision())); if (filterOutByDate && logEntry.getDate() == null) { // do not add lists without info - this situation is possible for lists where there are paths that user has no rights to observe return; @@ -399,6 +375,11 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi } } + private static void setCollectingChangesProgress(@Nullable Object location) { + ProgressManager.progress(SvnBundle.message("progress.text.changes.collecting.changes"), + SvnBundle.message("progress.text2.changes.establishing.connection", location)); + } + public ChangeListColumn[] getColumns() { return new ChangeListColumn[] { new ChangeListColumn.ChangeListNumberColumn(SvnBundle.message("revision.title")), From 0a1c3bbf1e7f4cf0ba04c3b0aa7e8489a764ca8c Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Wed, 5 Feb 2014 21:18:43 +0400 Subject: [PATCH 13/27] svn: Refactored SvnCommittedChangesProvider - method extractions, simplifications --- .../history/SvnCommittedChangesProvider.java | 152 +++++++++++------- 1 file changed, 97 insertions(+), 55 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java index efcd14cdeb7f..acf6c4630137 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java @@ -23,6 +23,7 @@ import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.ThrowableComputable; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vcs.*; import com.intellij.openapi.vcs.changes.Change; @@ -44,6 +45,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.*; import org.jetbrains.idea.svn.actions.ConfigureBranchesAction; +import org.jetbrains.idea.svn.commandLine.SvnBindException; import org.tmatesoft.svn.core.*; import org.tmatesoft.svn.core.internal.util.SVNPathUtil; import org.tmatesoft.svn.core.io.SVNRepository; @@ -179,7 +181,7 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi final String repositoryRoot = getRepositoryRoot(svnLocation); final ChangeBrowserSettings.Filter filter = settings.createFilter(); - getCommittedChangesImpl(settings, svnLocation.getURL(), new String[]{""}, maxCount, new Consumer() { + getCommittedChangesImpl(settings, svnLocation, new String[]{""}, maxCount, new Consumer() { public void consume(final SVNLogEntry svnLogEntry) { final SvnChangeList cl = new SvnChangeList(myVcs, svnLocation, svnLogEntry, repositoryRoot); if (filter.accepts(cl)) { @@ -198,7 +200,7 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi final ArrayList result = new ArrayList(); final String repositoryRoot = getRepositoryRoot(svnLocation); - getCommittedChangesImpl(settings, svnLocation.getURL(), new String[]{""}, maxCount, new Consumer() { + getCommittedChangesImpl(settings, svnLocation, new String[]{""}, maxCount, new Consumer() { public void consume(final SVNLogEntry svnLogEntry) { result.add(new SvnChangeList(myVcs, svnLocation, svnLogEntry, repositoryRoot)); } @@ -225,7 +227,7 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi } }); - getCommittedChangesImpl(settings, svnLocation.getURL(), new String[]{""}, maxCount, new Consumer() { + getCommittedChangesImpl(settings, svnLocation, new String[]{""}, maxCount, new Consumer() { public void consume(final SVNLogEntry svnLogEntry) { try { mergeSourceTracker.consume(svnLogEntry); @@ -306,75 +308,116 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi } } - private void getCommittedChangesImpl(ChangeBrowserSettings settings, final String url, final String[] filterUrls, + private void getCommittedChangesImpl(ChangeBrowserSettings settings, final SvnRepositoryLocation location, final String[] filterUrls, final int maxCount, final Consumer resultConsumer, final boolean includeMergedRevisions, final boolean filterOutByDate) throws VcsException { - setCollectingChangesProgress(url); + setCollectingChangesProgress(location); try { - SVNLogClient logger = myVcs.createLogClient(); - final String author = settings.getUserFilter(); final Date dateFrom = settings.getDateAfterFilter(); final Long changeFrom = settings.getChangeAfterFilter(); final Date dateTo = settings.getDateBeforeFilter(); final Long changeTo = settings.getChangeBeforeFilter(); - final SVNRevision revisionBefore; - if (dateTo != null) { - revisionBefore = SVNRevision.create(dateTo); - } - else if (changeTo != null) { - revisionBefore = SVNRevision.create(changeTo.longValue()); - } - else { - // TODO: Implement this with command line - SVNRepository repository = null; - final long revision; - try { - repository = myVcs.createRepository(url); - revision = repository.getLatestRevision(); - } finally { - if (repository != null) { - repository.closeSession(); - } - } - revisionBefore = SVNRevision.create(revision); - } - final SVNRevision revisionAfter; - if (dateFrom != null) { - revisionAfter = SVNRevision.create(dateFrom); - } - else if (changeFrom != null) { - revisionAfter = SVNRevision.create(changeFrom.longValue()); - } - else { - revisionAfter = SVNRevision.create(1); - } + final SVNRevision revisionBefore = createRevisionBefore(location, dateTo, changeTo); + final SVNRevision revisionAfter = createRevisionAfter(dateFrom, changeFrom); // TODO: Implement this with command line - logger.doLog(SVNURL.parseURIEncoded(url), filterUrls, revisionBefore, revisionBefore, revisionAfter, - settings.STOP_ON_COPY, true, includeMergedRevisions, maxCount, null, - new ISVNLogEntryHandler() { - public void handleLogEntry(SVNLogEntry logEntry) { - if (myProject.isDisposed()) throw new ProcessCanceledException(); - - ProgressManager.progress2(SvnBundle.message("progress.text2.processing.revision", logEntry.getRevision())); - if (filterOutByDate && logEntry.getDate() == null) { - // do not add lists without info - this situation is possible for lists where there are paths that user has no rights to observe - return; - } - if (author == null || author.equalsIgnoreCase(logEntry.getAuthor())) { - resultConsumer.consume(logEntry); - } - } - }); + SVNLogClient logger = myVcs.createLogClient(); + logger.doLog(location.toSvnUrl(), filterUrls, revisionBefore, revisionBefore, revisionAfter, settings.STOP_ON_COPY, true, + includeMergedRevisions, maxCount, null, createLogHandler(resultConsumer, filterOutByDate, author)); } catch (SVNException e) { throw new VcsException(e); } } + @NotNull + private static SVNRevision createRevisionAfter(@Nullable Date date, @Nullable Long change) throws VcsException { + return createRevision(date, change, new ThrowableComputable() { + @Override + public SVNRevision compute() throws VcsException { + return SVNRevision.create(1); + } + }); + } + + @NotNull + private SVNRevision createRevisionBefore(@NotNull final SvnRepositoryLocation location, @Nullable Date date, @Nullable Long change) + throws VcsException { + return createRevision(date, change, new ThrowableComputable() { + @Override + public SVNRevision compute() throws VcsException { + return getLatestRevision(location); + } + }); + } + + @NotNull + private SVNRevision getLatestRevision(@NotNull SvnRepositoryLocation location) throws VcsException { + // TODO: Implement this with command line - issue is that if url does not exist, SVNRepository will be created and asked correctly + // TODO: But "svn info -r HEAD" will fail - check if non-existing location could be passed or inteface should be expanded to use + // TODO: peg revisions. + SVNRepository repository = null; + long revision; + + try { + repository = myVcs.createRepository(location.getURL()); + revision = repository.getLatestRevision(); + } + catch (SVNException e) { + throw new SvnBindException(e); + } + finally { + if (repository != null) { + repository.closeSession(); + } + } + + return SVNRevision.create(revision); + } + + @NotNull + private static SVNRevision createRevision(@Nullable Date date, + @Nullable Long change, + @NotNull ThrowableComputable defaultValue) + throws VcsException { + final SVNRevision result; + + if (date != null) { + result = SVNRevision.create(date); + } + else if (change != null) { + result = SVNRevision.create(change.longValue()); + } + else { + result = defaultValue.compute(); + } + + return result; + } + + @NotNull + private ISVNLogEntryHandler createLogHandler(final Consumer resultConsumer, + final boolean filterOutByDate, + final String author) { + return new ISVNLogEntryHandler() { + public void handleLogEntry(SVNLogEntry logEntry) { + if (myProject.isDisposed()) throw new ProcessCanceledException(); + + ProgressManager.progress2(SvnBundle.message("progress.text2.processing.revision", logEntry.getRevision())); + if (filterOutByDate && logEntry.getDate() == null) { + // do not add lists without info - this situation is possible for lists where there are paths that user has no rights to observe + return; + } + if (author == null || author.equalsIgnoreCase(logEntry.getAuthor())) { + resultConsumer.consume(logEntry); + } + } + }; + } + private static void setCollectingChangesProgress(@Nullable Object location) { ProgressManager.progress(SvnBundle.message("progress.text.changes.collecting.changes"), SvnBundle.message("progress.text2.changes.establishing.connection", location)); @@ -458,7 +501,6 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi final RootUrlInfo rootUrlInfo = myVcs.getSvnFileUrlMapping().getWcRootForFilePath(new File(file.getPath())); if (rootUrlInfo == null) return null; final VirtualFile root = rootUrlInfo.getVirtualFile(); - if (root == null) return null; final SvnRepositoryLocation svnRootLocation = (SvnRepositoryLocation)getLocationFor(new FilePathImpl(root)); if (svnRootLocation == null) return null; final String url = svnRootLocation.getURL(); From bf1cadad6229845c0c114b52e2917f56c55d4cc8 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Wed, 5 Feb 2014 21:45:56 +0400 Subject: [PATCH 14/27] svn: Refactored SvnCommittedChangesProvider - inner classes moved to separate files and renamed --- .../history/MergeSourceHierarchyBuilder.java | 75 +++++++ .../svn/history/ShowHideMergePanelAction.java | 61 ++++++ .../history/SvnCommittedChangesProvider.java | 189 +----------------- .../svn/history/SvnCommittedListsZipper.java | 88 ++++++++ .../idea/svn/history/SvnCopyPathTracker.java | 83 ++++++++ 5 files changed, 316 insertions(+), 180 deletions(-) create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/history/MergeSourceHierarchyBuilder.java create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/history/ShowHideMergePanelAction.java create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedListsZipper.java create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCopyPathTracker.java diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/MergeSourceHierarchyBuilder.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/MergeSourceHierarchyBuilder.java new file mode 100644 index 000000000000..f0a77198925d --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/MergeSourceHierarchyBuilder.java @@ -0,0 +1,75 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.idea.svn.history; + +import com.intellij.openapi.util.Pair; +import com.intellij.util.Consumer; +import com.intellij.util.ThrowableConsumer; +import org.jetbrains.annotations.NotNull; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.SVNLogEntry; + +import java.util.List; + +/** +* @author Konstantin Kolosovsky. +*/ +public class MergeSourceHierarchyBuilder implements ThrowableConsumer, SVNException> { + + private TreeStructureNode myCurrentHierarchy; + @NotNull private final Consumer> myConsumer; + + public MergeSourceHierarchyBuilder(@NotNull Consumer> consumer) { + myConsumer = consumer; + } + + public void consume(Pair svnLogEntryIntegerPair) throws SVNException { + final SVNLogEntry logEntry = svnLogEntryIntegerPair.getFirst(); + final Integer mergeLevel = svnLogEntryIntegerPair.getSecond(); + + if (mergeLevel < 0) { + if (myCurrentHierarchy != null) { + myConsumer.consume(myCurrentHierarchy); + } + if (logEntry.hasChildren()) { + myCurrentHierarchy = new TreeStructureNode(logEntry); + } else { + // just pass + myCurrentHierarchy = null; + myConsumer.consume(new TreeStructureNode(logEntry)); + } + } else { + addToLevel(myCurrentHierarchy, logEntry, mergeLevel); + } + } + + public void finish() { + if (myCurrentHierarchy != null) { + myConsumer.consume(myCurrentHierarchy); + } + } + + private static void addToLevel(final TreeStructureNode tree, final SVNLogEntry entry, final int left) { + assert tree != null; + if (left == 0) { + tree.add(entry); + } else { + final List> children = tree.getChildren(); + assert ! children.isEmpty(); + addToLevel(children.get(children.size() - 1), entry, left - 1); + } + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/ShowHideMergePanelAction.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/ShowHideMergePanelAction.java new file mode 100644 index 000000000000..570167f7f90f --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/ShowHideMergePanelAction.java @@ -0,0 +1,61 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.idea.svn.history; + +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.Presentation; +import com.intellij.openapi.actionSystem.ToggleAction; +import com.intellij.openapi.vcs.changes.committed.ChangeListFilteringStrategy; +import com.intellij.openapi.vcs.changes.committed.DecoratorManager; +import icons.SvnIcons; +import org.jetbrains.idea.svn.SvnBundle; + +/** +* @author Konstantin Kolosovsky. +*/ +public class ShowHideMergePanelAction extends ToggleAction { + + private final DecoratorManager myManager; + private final ChangeListFilteringStrategy myStrategy; + private boolean myIsSelected; + + public ShowHideMergePanelAction(final DecoratorManager manager, final ChangeListFilteringStrategy strategy) { + myManager = manager; + myStrategy = strategy; + } + + @Override + public void update(final AnActionEvent e) { + super.update(e); + final Presentation presentation = e.getPresentation(); + presentation.setIcon(SvnIcons.ShowIntegratedFrom); + presentation.setText(SvnBundle.message("committed.changes.action.enable.merge.highlighting")); + presentation.setDescription(SvnBundle.message("committed.changes.action.enable.merge.highlighting.description.text")); + } + + public boolean isSelected(final AnActionEvent e) { + return myIsSelected; + } + + public void setSelected(final AnActionEvent e, final boolean state) { + myIsSelected = state; + if (state) { + myManager.setFilteringStrategy(myStrategy); + } else { + myManager.removeFilteringStrategy(myStrategy.getKey()); + } + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java index acf6c4630137..11f4b4ce7e97 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java @@ -38,9 +38,7 @@ import com.intellij.util.AsynchConsumer; import com.intellij.util.Consumer; import com.intellij.util.PairConsumer; import com.intellij.util.ThrowableConsumer; -import com.intellij.util.containers.MultiMap; import com.intellij.util.messages.MessageBusConnection; -import icons.SvnIcons; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.*; @@ -67,7 +65,7 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi private final SvnVcs myVcs; private final MessageBusConnection myConnection; private MergeInfoUpdatesListener myMergeInfoUpdatesListener; - private final MyZipper myZipper; + private final SvnCommittedListsZipper myZipper; public final static int VERSION_WITH_COPY_PATHS_ADDED = 2; public final static int VERSION_WITH_REPLACED_PATHS = 3; @@ -77,7 +75,7 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi public SvnCommittedChangesProvider(final Project project) { myProject = project; myVcs = SvnVcs.getInstance(myProject); - myZipper = new MyZipper(); + myZipper = new SvnCommittedListsZipper(myVcs); myConnection = myProject.getMessageBus().connect(); @@ -128,49 +126,6 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi return myZipper; } - private class MyZipper implements VcsCommittedListsZipper { - public Pair, List> groupLocations(final List in) { - final List groups = new ArrayList(); - final List singles = new ArrayList(); - - final MultiMap map = new MultiMap(); - - for (RepositoryLocation location : in) { - final SvnRepositoryLocation svnLocation = (SvnRepositoryLocation) location; - final String url = svnLocation.getURL(); - - final SVNURL root = SvnUtil.getRepositoryRoot(myVcs, url); - if (root == null) { - // should not occur - LOG.info("repository root not found for location:"+ location.toPresentableString()); - singles.add(location); - } else { - map.putValue(root, svnLocation); - } - } - - final Set keys = map.keySet(); - for (SVNURL key : keys) { - final Collection repositoryLocations = map.get(key); - if (repositoryLocations.size() == 1) { - singles.add(repositoryLocations.iterator().next()); - } else { - final SvnRepositoryLocationGroup group = new SvnRepositoryLocationGroup(key, repositoryLocations); - groups.add(group); - } - } - return new Pair, List>(groups, singles); - } - - public CommittedChangeList zip(final RepositoryLocationGroup group, final List lists) { - return new SvnChangeList(lists, new SvnRepositoryLocation(group.toPresentableString())); - } - - public long getNumber(final CommittedChangeList list) { - return list.getNumber(); - } - } - public void loadCommittedChanges(ChangeBrowserSettings settings, RepositoryLocation location, int maxCount, @@ -216,14 +171,14 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi final SvnRepositoryLocation svnLocation = (SvnRepositoryLocation) location; final String repositoryRoot = getRepositoryRoot(svnLocation); - final MergeTrackerProxy proxy = new MergeTrackerProxy(new Consumer>() { + final MergeSourceHierarchyBuilder builder = new MergeSourceHierarchyBuilder(new Consumer>() { public void consume(TreeStructureNode node) { finalConsumer.consume(new SvnChangeList(myVcs, svnLocation, node.getMe(), repositoryRoot), node); } }); final SvnMergeSourceTracker mergeSourceTracker = new SvnMergeSourceTracker(new ThrowableConsumer, SVNException>() { public void consume(Pair svnLogEntryIntegerPair) throws SVNException { - proxy.consume(svnLogEntryIntegerPair); + builder.consume(svnLogEntryIntegerPair); } }); @@ -239,7 +194,7 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi } }, true, false); - proxy.finish(); + builder.finish(); } private String getRepositoryRoot(@NotNull SvnRepositoryLocation svnLocation) throws VcsException { @@ -262,52 +217,6 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi return repositoryRoot; } - private static class MergeTrackerProxy implements ThrowableConsumer, SVNException> { - private TreeStructureNode myCurrentHierarchy; - private final Consumer> myConsumer; - - private MergeTrackerProxy(Consumer> consumer) { - myConsumer = consumer; - } - - public void consume(Pair svnLogEntryIntegerPair) throws SVNException { - final SVNLogEntry logEntry = svnLogEntryIntegerPair.getFirst(); - final Integer mergeLevel = svnLogEntryIntegerPair.getSecond(); - - if (mergeLevel < 0) { - if (myCurrentHierarchy != null) { - myConsumer.consume(myCurrentHierarchy); - } - if (logEntry.hasChildren()) { - myCurrentHierarchy = new TreeStructureNode(logEntry); - } else { - // just pass - myCurrentHierarchy = null; - myConsumer.consume(new TreeStructureNode(logEntry)); - } - } else { - addToLevel(myCurrentHierarchy, logEntry, mergeLevel); - } - } - - public void finish() { - if (myCurrentHierarchy != null) { - myConsumer.consume(myCurrentHierarchy); - } - } - - private static void addToLevel(final TreeStructureNode tree, final SVNLogEntry entry, final int left) { - assert tree != null; - if (left == 0) { - tree.add(entry); - } else { - final List> children = tree.getChildren(); - assert ! children.isEmpty(); - addToLevel(children.get(children.size() - 1), entry, left - 1); - } - } - } - private void getCommittedChangesImpl(ChangeBrowserSettings settings, final SvnRepositoryLocation location, final String[] filterUrls, final int maxCount, final Consumer resultConsumer, final boolean includeMergedRevisions, final boolean filterOutByDate) throws VcsException { @@ -437,39 +346,6 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi myMergeInfoUpdatesListener.addPanel(action); } - private static class ShowHideMergePanel extends ToggleAction { - private final DecoratorManager myManager; - private final ChangeListFilteringStrategy myStrategy; - private boolean myIsSelected; - - public ShowHideMergePanel(final DecoratorManager manager, final ChangeListFilteringStrategy strategy) { - myManager = manager; - myStrategy = strategy; - } - - @Override - public void update(final AnActionEvent e) { - super.update(e); - final Presentation presentation = e.getPresentation(); - presentation.setIcon(SvnIcons.ShowIntegratedFrom); - presentation.setText(SvnBundle.message("committed.changes.action.enable.merge.highlighting")); - presentation.setDescription(SvnBundle.message("committed.changes.action.enable.merge.highlighting.description.text")); - } - - public boolean isSelected(final AnActionEvent e) { - return myIsSelected; - } - - public void setSelected(final AnActionEvent e, final boolean state) { - myIsSelected = state; - if (state) { - myManager.setFilteringStrategy(myStrategy); - } else { - myManager.removeFilteringStrategy(myStrategy.getKey()); - } - } - } - @Nullable public VcsCommittedViewAuxiliary createActions(final DecoratorManager manager, @Nullable final RepositoryLocation location) { final RootsAndBranches rootsAndBranches = new RootsAndBranches(myProject, manager, location); @@ -480,7 +356,7 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi popup.add(rootsAndBranches.getUndoIntegrateAction()); popup.add(new ConfigureBranchesAction()); - final ShowHideMergePanel action = new ShowHideMergePanel(manager, rootsAndBranches.getStrategy()); + final ShowHideMergePanelAction action = new ShowHideMergePanelAction(manager, rootsAndBranches.getStrategy()); return new VcsCommittedViewAuxiliary(Collections.singletonList(popup), new Runnable() { public void run() { @@ -577,53 +453,6 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi return true; } - private static class RenameContext { - @NotNull - private String myCurrentPath; - private String myRepositoryRoot; - private boolean myHadChanged; - - private RenameContext(final SVNInfo info) { - myRepositoryRoot = info.getRepositoryRootURL().toString(); - myCurrentPath = SVNPathUtil.getRelativePath(myRepositoryRoot, info.getURL().toString()); - myCurrentPath = myCurrentPath.startsWith("/") ? myCurrentPath : ("/" + myCurrentPath); - } - - public void accept(final SVNLogEntry entry) { - final Map changedPaths = entry.getChangedPaths(); - if (changedPaths == null) return; - - for (Object o : changedPaths.values()) { - final SVNLogEntryPath entryPath = (SVNLogEntryPath) o; - if (entryPath != null && 'A' == entryPath.getType() && entryPath.getCopyPath() != null) { - if (myCurrentPath.equals(entryPath.getPath())) { - myHadChanged = true; - myCurrentPath = entryPath.getCopyPath(); - return; - } else if (SVNPathUtil.isAncestor(entryPath.getPath(), myCurrentPath)) { - final String relativePath = SVNPathUtil.getRelativePath(entryPath.getPath(), myCurrentPath); - myCurrentPath = SVNPathUtil.append(entryPath.getCopyPath(), relativePath); - myHadChanged = true; - return; - } - } - } - } - - @Nullable - public FilePath getFilePath(final SvnVcs vcs) { - if (! myHadChanged) return null; - final SvnFileUrlMapping svnFileUrlMapping = vcs.getSvnFileUrlMapping(); - final String absolutePath = SVNPathUtil.append(myRepositoryRoot, myCurrentPath); - final String localPath = svnFileUrlMapping.getLocalPath(absolutePath); - if (localPath == null) { - LOG.info("Cannot find local path for url: " + absolutePath); - return null; - } - return new FilePathImpl(new File(localPath), false); - } - } - private void tryByRoot(SvnChangeList[] result, SVNLogClient logger, SVNRevision revisionBefore, SVNURL repositoryUrl) throws VcsException { final boolean authorized = SvnAuthenticationNotifier.passiveValidation(myProject, repositoryUrl); if (! authorized) return; @@ -637,7 +466,7 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi final SVNRevision revisionBefore, final SVNInfo info, SVNURL svnurl) throws VcsException { final String repositoryRoot = info.getRepositoryRootURL().toString(); try { - final RenameContext renameContext = new RenameContext(info); + final SvnCopyPathTracker pathTracker = new SvnCopyPathTracker(info); // TODO: Implement this with command line logger.doLog(svnurl, null, SVNRevision.UNDEFINED, SVNRevision.HEAD, revisionBefore, false, true, false, 0, null, @@ -648,13 +477,13 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi // do not add lists without info - this situation is possible for lists where there are paths that user has no rights to observe return; } - renameContext.accept(logEntry); + pathTracker.accept(logEntry); if (logEntry.getRevision() == revisionBefore.getNumber()) { result[0] = new SvnChangeList(myVcs, svnRepositoryLocation, logEntry, repositoryRoot); } } }); - return renameContext.getFilePath(myVcs); + return pathTracker.getFilePath(myVcs); } catch (SVNException e) { LOG.info(e); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedListsZipper.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedListsZipper.java new file mode 100644 index 000000000000..13359c4d5f23 --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedListsZipper.java @@ -0,0 +1,88 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.idea.svn.history; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.vcs.RepositoryLocation; +import com.intellij.openapi.vcs.changes.committed.RepositoryLocationGroup; +import com.intellij.openapi.vcs.changes.committed.VcsCommittedListsZipper; +import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList; +import com.intellij.util.containers.MultiMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.svn.SvnUtil; +import org.jetbrains.idea.svn.SvnVcs; +import org.tmatesoft.svn.core.SVNURL; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Set; + +/** +* @author Konstantin Kolosovsky. +*/ +public class SvnCommittedListsZipper implements VcsCommittedListsZipper { + + private static final Logger LOG = Logger.getInstance(SvnCommittedListsZipper.class); + + @NotNull private final SvnVcs myVcs; + + public SvnCommittedListsZipper(@NotNull SvnVcs vcs) { + myVcs = vcs; + } + + public Pair, List> groupLocations(final List in) { + final List groups = new ArrayList(); + final List singles = new ArrayList(); + + final MultiMap map = new MultiMap(); + + for (RepositoryLocation location : in) { + final SvnRepositoryLocation svnLocation = (SvnRepositoryLocation) location; + final String url = svnLocation.getURL(); + + final SVNURL root = SvnUtil.getRepositoryRoot(myVcs, url); + if (root == null) { + // should not occur + LOG.info("repository root not found for location:"+ location.toPresentableString()); + singles.add(location); + } else { + map.putValue(root, svnLocation); + } + } + + final Set keys = map.keySet(); + for (SVNURL key : keys) { + final Collection repositoryLocations = map.get(key); + if (repositoryLocations.size() == 1) { + singles.add(repositoryLocations.iterator().next()); + } else { + final SvnRepositoryLocationGroup group = new SvnRepositoryLocationGroup(key, repositoryLocations); + groups.add(group); + } + } + return new Pair, List>(groups, singles); + } + + public CommittedChangeList zip(final RepositoryLocationGroup group, final List lists) { + return new SvnChangeList(lists, new SvnRepositoryLocation(group.toPresentableString())); + } + + public long getNumber(final CommittedChangeList list) { + return list.getNumber(); + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCopyPathTracker.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCopyPathTracker.java new file mode 100644 index 000000000000..93326dc3a108 --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCopyPathTracker.java @@ -0,0 +1,83 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.idea.svn.history; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.vcs.FilePath; +import com.intellij.openapi.vcs.FilePathImpl; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.svn.SvnFileUrlMapping; +import org.jetbrains.idea.svn.SvnVcs; +import org.tmatesoft.svn.core.SVNLogEntry; +import org.tmatesoft.svn.core.SVNLogEntryPath; +import org.tmatesoft.svn.core.internal.util.SVNPathUtil; +import org.tmatesoft.svn.core.wc.SVNInfo; + +import java.io.File; +import java.util.Map; + +/** +* @author Konstantin Kolosovsky. +*/ +public class SvnCopyPathTracker { + + private static final Logger LOG = Logger.getInstance(SvnCopyPathTracker.class); + + @NotNull private String myCurrentPath; + private String myRepositoryRoot; + private boolean myHadChanged; + + public SvnCopyPathTracker(@NotNull final SVNInfo info) { + myRepositoryRoot = info.getRepositoryRootURL().toString(); + myCurrentPath = SVNPathUtil.getRelativePath(myRepositoryRoot, info.getURL().toString()); + myCurrentPath = myCurrentPath.startsWith("/") ? myCurrentPath : ("/" + myCurrentPath); + } + + public void accept(@NotNull final SVNLogEntry entry) { + final Map changedPaths = entry.getChangedPaths(); + if (changedPaths == null) return; + + for (Object o : changedPaths.values()) { + final SVNLogEntryPath entryPath = (SVNLogEntryPath) o; + if (entryPath != null && 'A' == entryPath.getType() && entryPath.getCopyPath() != null) { + if (myCurrentPath.equals(entryPath.getPath())) { + myHadChanged = true; + myCurrentPath = entryPath.getCopyPath(); + return; + } else if (SVNPathUtil.isAncestor(entryPath.getPath(), myCurrentPath)) { + final String relativePath = SVNPathUtil.getRelativePath(entryPath.getPath(), myCurrentPath); + myCurrentPath = SVNPathUtil.append(entryPath.getCopyPath(), relativePath); + myHadChanged = true; + return; + } + } + } + } + + @Nullable + public FilePath getFilePath(final SvnVcs vcs) { + if (! myHadChanged) return null; + final SvnFileUrlMapping svnFileUrlMapping = vcs.getSvnFileUrlMapping(); + final String absolutePath = SVNPathUtil.append(myRepositoryRoot, myCurrentPath); + final String localPath = svnFileUrlMapping.getLocalPath(absolutePath); + if (localPath == null) { + LOG.info("Cannot find local path for url: " + absolutePath); + return null; + } + return new FilePathImpl(new File(localPath), false); + } +} From 0c9d76ee0915eaf9fe74434589fe458f13609989 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Thu, 6 Feb 2014 17:15:33 +0400 Subject: [PATCH 15/27] svn: Refactored SvnCommittedChangesProvider.getOneList - simplify code flow --- .../src/com/intellij/vcsUtil/VcsUtil.java | 4 + .../history/SvnCommittedChangesProvider.java | 115 ++++++++++-------- 2 files changed, 68 insertions(+), 51 deletions(-) diff --git a/platform/vcs-api/src/com/intellij/vcsUtil/VcsUtil.java b/platform/vcs-api/src/com/intellij/vcsUtil/VcsUtil.java index eafd649b3686..9f9e261657f3 100644 --- a/platform/vcs-api/src/com/intellij/vcsUtil/VcsUtil.java +++ b/platform/vcs-api/src/com/intellij/vcsUtil/VcsUtil.java @@ -310,6 +310,10 @@ public class VcsUtil { return getFilePath(new File(path)); } + public static FilePath getFilePath(@NotNull VirtualFile file) { + return VcsContextFactory.SERVICE.getInstance().createFilePathOn(file); + } + public static FilePath getFilePath(File file) { return VcsContextFactory.SERVICE.getInstance().createFilePathOn(file); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java index 11f4b4ce7e97..d046e79ff76d 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java @@ -16,7 +16,8 @@ package org.jetbrains.idea.svn.history; -import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProcessCanceledException; @@ -28,7 +29,10 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vcs.*; import com.intellij.openapi.vcs.changes.Change; import com.intellij.openapi.vcs.changes.ContentRevision; -import com.intellij.openapi.vcs.changes.committed.*; +import com.intellij.openapi.vcs.changes.committed.DecoratorManager; +import com.intellij.openapi.vcs.changes.committed.VcsCommittedListsZipper; +import com.intellij.openapi.vcs.changes.committed.VcsCommittedViewAuxiliary; +import com.intellij.openapi.vcs.changes.committed.VcsConfigurationChangeListener; import com.intellij.openapi.vcs.history.VcsRevisionNumber; import com.intellij.openapi.vcs.versionBrowser.ChangeBrowserSettings; import com.intellij.openapi.vcs.versionBrowser.ChangesBrowserSettingsEditor; @@ -38,7 +42,9 @@ import com.intellij.util.AsynchConsumer; import com.intellij.util.Consumer; import com.intellij.util.PairConsumer; import com.intellij.util.ThrowableConsumer; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.messages.MessageBusConnection; +import com.intellij.vcsUtil.VcsUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.*; @@ -410,36 +416,42 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi throw new VcsException(e); } - tryExactHit(svnRootLocation, result, logger, revisionBefore, repositoryUrl, svnurl); - if (result[0] == null) { - tryByRoot(result, logger, revisionBefore, repositoryUrl); - if (result[0] == null) { - FilePath path = tryStepByStep(svnRootLocation, result, logger, revisionBefore, targetInfo, svnurl); - path = path == null ? new FilePathImpl(file) : path; - // and pass & take rename context there - return new Pair(result[0], path); + FilePath filePath = VcsUtil.getFilePath(file); + + if (!tryExactHit(svnRootLocation, result, logger, revisionBefore, repositoryUrl, svnurl) && + !tryByRoot(result, logger, revisionBefore, repositoryUrl)) { + filePath = getOneListStepByStep(svnRootLocation, result, logger, revisionBefore, svnurl, targetInfo, filePath); + } + else { + Change change = ContainerUtil.getFirstItem(result[0].getChanges()); + if (change != null) { + final ContentRevision afterRevision = change.getAfterRevision(); + + filePath = afterRevision != null ? afterRevision.getFile() : filePath; + } + else { + String relativePath = SVNPathUtil.getRelativePath(targetInfo.getRepositoryRootURL().toString(), targetInfo.getURL().toString()); + relativePath = relativePath.startsWith("/") ? relativePath : "/" + relativePath; + final Change targetChange = result[0].getByPath(relativePath); + + filePath = targetChange == null + ? getOneListStepByStep(svnRootLocation, result, logger, revisionBefore, svnurl, targetInfo, filePath) + : filePath; } } - if (result[0].getChanges().size() == 1) { - final Collection changes = result[0].getChanges(); - final Change change = changes.iterator().next(); - final ContentRevision afterRevision = change.getAfterRevision(); - if (afterRevision != null) { - return new Pair(result[0], afterRevision.getFile()); - } else { - return new Pair(result[0], new FilePathImpl(file)); - } - } - String relativePath = SVNPathUtil.getRelativePath(targetInfo.getRepositoryRootURL().toString(), targetInfo.getURL().toString()); - relativePath = relativePath.startsWith("/") ? relativePath : "/" + relativePath; - final Change targetChange = result[0].getByPath(relativePath); - if (targetChange == null) { - FilePath path = tryStepByStep(svnRootLocation, result, logger, revisionBefore, targetInfo, svnurl); - path = path == null ? new FilePathImpl(file) : path; - // and pass & take rename context there - return new Pair(result[0], path); - } - return new Pair(result[0], new FilePathImpl(file)); + + return Pair.create(result[0], filePath); + } + + private FilePath getOneListStepByStep(SvnRepositoryLocation svnRootLocation, + SvnChangeList[] result, + SVNLogClient logger, + SVNRevision revisionBefore, + SVNURL svnurl, + SVNInfo targetInfo, FilePath filePath) throws VcsException { + FilePath path = tryStepByStep(svnRootLocation, result, logger, revisionBefore, targetInfo, svnurl); + + return path == null ? filePath : path; } @Override @@ -453,10 +465,12 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi return true; } - private void tryByRoot(SvnChangeList[] result, SVNLogClient logger, SVNRevision revisionBefore, SVNURL repositoryUrl) throws VcsException { + private boolean tryByRoot(SvnChangeList[] result, SVNLogClient logger, SVNRevision revisionBefore, SVNURL repositoryUrl) + throws VcsException { final boolean authorized = SvnAuthenticationNotifier.passiveValidation(myProject, repositoryUrl); - if (! authorized) return; - tryExactHit(new SvnRepositoryLocation(repositoryUrl.toString()), result, logger, revisionBefore, repositoryUrl, repositoryUrl); + + return authorized && + tryExactHit(new SvnRepositoryLocation(repositoryUrl.toString()), result, logger, revisionBefore, repositoryUrl, repositoryUrl); } // return changed path, if any @@ -491,34 +505,33 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi } } - private void tryExactHit(final SvnRepositoryLocation location, - final SvnChangeList[] result, + private boolean tryExactHit(final SvnRepositoryLocation location, + final SvnChangeList[] result, SVNLogClient logger, SVNRevision revisionBefore, final SVNURL repositoryUrl, SVNURL svnurl) throws VcsException { + + ISVNLogEntryHandler handler = new ISVNLogEntryHandler() { + public void handleLogEntry(SVNLogEntry logEntry) { + if (myProject.isDisposed()) throw new ProcessCanceledException(); + if (logEntry.getDate() == null) { + // do not add lists without info - this situation is possible for lists where there are paths that user has no rights to observe + return; + } + result[0] = new SvnChangeList(myVcs, location, logEntry, repositoryUrl.toString()); + } + }; try { // TODO: Implement this with command line - logger.doLog(svnurl, null, SVNRevision.UNDEFINED, revisionBefore, revisionBefore, - false, true, false, 1, null, - new ISVNLogEntryHandler() { - public void handleLogEntry(SVNLogEntry logEntry) { - if (myProject.isDisposed()) throw new ProcessCanceledException(); - if (logEntry.getDate() == null) { - // do not add lists without info - this situation is possible for lists where there are paths that user has no rights to observe - return; - } - result[0] = new SvnChangeList(myVcs, location, logEntry, repositoryUrl.toString()); - } - }); + logger.doLog(svnurl, null, SVNRevision.UNDEFINED, revisionBefore, revisionBefore, false, true, false, 1, null, handler); } catch (SVNException e) { LOG.info(e); - if (SVNErrorCode.FS_CATEGORY == e.getErrorMessage().getErrorCode().getCategory()) { - // pass to step by step looking for revision - return; + if (SVNErrorCode.FS_CATEGORY != e.getErrorMessage().getErrorCode().getCategory()) { + throw new VcsException(e); } - throw new VcsException(e); } + return result[0] != null; } public int getFormatVersion() { From feced992b9baa8b561cd9c42aa7853116c8395d9 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Thu, 6 Feb 2014 17:57:29 +0400 Subject: [PATCH 16/27] svn: Removed unnecessary SvnLoadingRepositoryLocation --- .../history/SvnCommittedChangesProvider.java | 6 +--- .../history/SvnLoadingRepositoryLocation.java | 35 ------------------- 2 files changed, 1 insertion(+), 40 deletions(-) delete mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnLoadingRepositoryLocation.java diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java index d046e79ff76d..adb4adf4d372 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java @@ -120,11 +120,7 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi } public RepositoryLocation getLocationFor(final FilePath root, final String repositoryPath) { - if (repositoryPath == null) { - return getLocationFor(root); - } - - return new SvnLoadingRepositoryLocation(repositoryPath, myVcs); + return repositoryPath == null ? getLocationFor(root) : new SvnRepositoryLocation(repositoryPath); } @Nullable diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnLoadingRepositoryLocation.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnLoadingRepositoryLocation.java deleted file mode 100644 index 3fcc5c32c94f..000000000000 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnLoadingRepositoryLocation.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jetbrains.idea.svn.history; - -import com.intellij.openapi.vcs.FilePath; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.idea.svn.SvnVcs; - -public class SvnLoadingRepositoryLocation extends SvnRepositoryLocation { - private final LocationDetector locationDetector; - - public SvnLoadingRepositoryLocation(final FilePath rootFile, @NotNull final String URL, @NotNull final SvnVcs vcs) { - super(URL); - locationDetector = new LocationDetector(vcs); - } - - public SvnLoadingRepositoryLocation(@NotNull final String URL, @NotNull final SvnVcs vcs) { - super(URL); - locationDetector = new LocationDetector(vcs); - } - -} From 486a6086c1fc6435165d1f6a7a86d4b6229618ff Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Thu, 6 Feb 2014 18:28:50 +0400 Subject: [PATCH 17/27] svn: Removed unnecessary LocationDetector and accompanying logic --- .../src/org/jetbrains/idea/svn/SvnUtil.java | 39 ++--------- .../idea/svn/history/LocationDetector.java | 64 ------------------- .../svn/history/SvnRepositoryLocation.java | 10 ++- 3 files changed, 12 insertions(+), 101 deletions(-) delete mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/history/LocationDetector.java diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java index 6a86c7ac2e89..c47c5624ba37 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java @@ -152,12 +152,6 @@ public class SvnUtil { return info != null && info.getURL() != null ? info.getURL().toString() : null; } - public static Map getLocationInfoForModule(final SvnVcs vcs, File path, ProgressIndicator progress) { - final LocationsCrawler crawler = new LocationsCrawler(vcs); - crawlWCRoots(vcs.getProject(), path, crawler, progress); - return crawler.getLocationInfos(); - } - public static void doLockFiles(Project project, final SvnVcs activeVcs, @NotNull final File[] ioFiles) throws VcsException { final String lockMessage; final boolean force; @@ -414,35 +408,6 @@ public class SvnUtil { return result; } - private static class LocationsCrawler implements SvnWCRootCrawler { - private final SvnVcs myVcs; - private final Map myLocations; - - public LocationsCrawler(SvnVcs vcs) { - myVcs = vcs; - myLocations = new HashMap(); - } - - public Map getLocationInfos() { - return Collections.unmodifiableMap(myLocations); - } - - public void handleWorkingCopyRoot(File root, ProgressIndicator progress) { - String oldText = null; - if (progress != null) { - oldText = progress.getText(); - progress.setText(SvnBundle.message("progress.text.discovering.location", root.getAbsolutePath())); - } - SVNInfo info = myVcs.getInfo(root); - if (info != null && info.getURL() != null) { - myLocations.put(info.getURL().toString(), info.getFile()); - } - if (progress != null) { - progress.setText(oldText); - } - } - } - @Nullable public static String getRepositoryUUID(final SvnVcs vcs, final File file) { final SVNInfo info = vcs.getInfo(file); @@ -740,6 +705,10 @@ public class SvnUtil { } } + public static String getRelativeUrl(@NotNull String parentUrl, @NotNull String childUrl) { + return FileUtilRt.getRelativePath(parentUrl, childUrl, '/', true); + } + public static String appendMultiParts(@NotNull final String base, @NotNull final String subPath) { if (StringUtil.isEmpty(subPath)) return base; final List parts = StringUtil.split(subPath.replace('\\', '/'), "/", true); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/LocationDetector.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/LocationDetector.java deleted file mode 100644 index 55cc740e17a8..000000000000 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/LocationDetector.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jetbrains.idea.svn.history; - -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.ProgressManager; -import com.intellij.openapi.vcs.FilePath; -import com.intellij.openapi.vcs.ProjectLevelVcsManager; -import com.intellij.openapi.vcs.actions.VcsContextFactory; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.NotNullFunction; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.idea.svn.SvnUtil; -import org.jetbrains.idea.svn.SvnVcs; -import org.tmatesoft.svn.core.internal.util.SVNPathUtil; - -import java.io.File; -import java.util.HashMap; -import java.util.Map; - -public class LocationDetector { - private final Map myMap; - - public LocationDetector(final SvnVcs vcs) { - myMap = new HashMap(); - - final ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator(); - final VirtualFile[] roots = ProjectLevelVcsManager.getInstance(vcs.getProject()).getRootsUnderVcs(vcs); - - for (VirtualFile root : roots) { - myMap.putAll(SvnUtil.getLocationInfoForModule(vcs, new File(root.getPath()), progress)); - } - } - - @Nullable - public FilePath crawlForPath(final String fullPath, final NotNullFunction detector) { - for (Map.Entry entry : myMap.entrySet()) { - final String url = entry.getKey(); - if (SVNPathUtil.isAncestor(url, fullPath)) { - return filePathByUrlAndPath(fullPath, url, entry.getValue().getAbsolutePath(), detector); - } - } - return null; - } - - static FilePath filePathByUrlAndPath(final String longPath, final String parentUrl, final String parentPath, final NotNullFunction detector) { - final String relPath = longPath.substring(parentUrl.length()); - final File localFile = new File(parentPath, relPath); - return VcsContextFactory.SERVICE.getInstance().createFilePathOn(localFile, detector); - } -} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnRepositoryLocation.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnRepositoryLocation.java index 7290f0030032..5dc605b8ed57 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnRepositoryLocation.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnRepositoryLocation.java @@ -18,6 +18,7 @@ package org.jetbrains.idea.svn.history; import com.intellij.openapi.vcs.FilePath; import com.intellij.openapi.vcs.RepositoryLocation; import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vcs.actions.VcsContextFactory; import com.intellij.util.NotNullFunction; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.RootUrlInfo; @@ -67,11 +68,16 @@ public class SvnRepositoryLocation implements RepositoryLocation { public static FilePath getLocalPath(final String fullPath, final NotNullFunction detector, final SvnVcs vcs) { if (vcs.getProject().isDefault()) return null; final RootUrlInfo rootForUrl = vcs.getSvnFileUrlMapping().getWcRootForUrl(fullPath); + FilePath result = null; + if (rootForUrl != null) { - return LocationDetector.filePathByUrlAndPath(fullPath, rootForUrl.getUrl().toString(), rootForUrl.getIoFile().getAbsolutePath(), detector); + String relativePath = SvnUtil.getRelativeUrl(rootForUrl.getUrl(), fullPath); + File file = new File(rootForUrl.getPath(), relativePath); + + result = VcsContextFactory.SERVICE.getInstance().createFilePathOn(file, detector); } - return null; + return result; } public SVNURL toSvnUrl() throws VcsException { From 26d23a9b09659b61b967d3e1f909901632c6f6b1 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Thu, 6 Feb 2014 22:16:45 +0400 Subject: [PATCH 18/27] svn: Refactored SvnCommittedChangesProvider.getOneList - simplify parameters detection (use already existing objects instead of executing svn commands again) --- .../src/org/jetbrains/idea/svn/SvnUtil.java | 13 ++++ .../history/SvnCommittedChangesProvider.java | 71 ++++++------------- .../idea/svn/history/SvnCopyPathTracker.java | 8 +-- 3 files changed, 38 insertions(+), 54 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java index c47c5624ba37..7a28423d474e 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java @@ -709,6 +709,19 @@ public class SvnUtil { return FileUtilRt.getRelativePath(parentUrl, childUrl, '/', true); } + public static String getRelativePath(@NotNull String parentPath, @NotNull String childPath) { + return FileUtilRt.getRelativePath(FileUtil.toSystemIndependentName(parentPath), FileUtil.toSystemIndependentName(childPath), '/'); + } + + public static String ensureStartSlash(@NotNull String path) { + return StringUtil.startsWithChar(path, '/') ? path : '/' + path; + } + + @NotNull + public static String join(@NotNull final String... parts) { + return StringUtil.join(parts, "/"); + } + public static String appendMultiParts(@NotNull final String base, @NotNull final String subPath) { if (StringUtil.isEmpty(subPath)) return base; final List parts = StringUtil.split(subPath.replace('\\', '/'), "/", true); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java index adb4adf4d372..6620f3fe1774 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java @@ -51,9 +51,7 @@ import org.jetbrains.idea.svn.*; import org.jetbrains.idea.svn.actions.ConfigureBranchesAction; import org.jetbrains.idea.svn.commandLine.SvnBindException; import org.tmatesoft.svn.core.*; -import org.tmatesoft.svn.core.internal.util.SVNPathUtil; import org.tmatesoft.svn.core.io.SVNRepository; -import org.tmatesoft.svn.core.wc.SVNInfo; import org.tmatesoft.svn.core.wc.SVNLogClient; import org.tmatesoft.svn.core.wc.SVNRevision; @@ -378,45 +376,23 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi public Pair getOneList(final VirtualFile file, VcsRevisionNumber number) throws VcsException { final RootUrlInfo rootUrlInfo = myVcs.getSvnFileUrlMapping().getWcRootForFilePath(new File(file.getPath())); if (rootUrlInfo == null) return null; - final VirtualFile root = rootUrlInfo.getVirtualFile(); - final SvnRepositoryLocation svnRootLocation = (SvnRepositoryLocation)getLocationFor(new FilePathImpl(root)); - if (svnRootLocation == null) return null; - final String url = svnRootLocation.getURL(); - final long revision; - try { - revision = Long.parseLong(number.asString()); - } catch (NumberFormatException e) { - throw new VcsException(e); - } final SvnChangeList[] result = new SvnChangeList[1]; - final SVNLogClient logger; - final SVNRevision revisionBefore; - final SVNURL repositoryUrl; - final SVNURL svnurl; - final SVNInfo targetInfo; - try { - logger = myVcs.createLogClient(); - revisionBefore = SVNRevision.create(revision); - - svnurl = SVNURL.parseURIEncoded(url); - final SVNInfo info = myVcs.getInfo(svnurl, SVNRevision.HEAD); - targetInfo = myVcs.getInfo(new File(file.getPath())); - if (info == null) { - throw new VcsException("Can not get repository URL"); - } - repositoryUrl = info.getRepositoryRootURL(); - } - catch (SVNException e) { - LOG.info(e); - throw new VcsException(e); - } + final SVNRevision revisionBefore = ((SvnRevisionNumber)number).getRevision(); + final SVNURL repositoryUrl = rootUrlInfo.getRepositoryUrlUrl(); + final SVNURL svnRootUrl = rootUrlInfo.getAbsoluteUrlAsUrl(); + final SvnRepositoryLocation svnRootLocation = new SvnRepositoryLocation(rootUrlInfo.getAbsoluteUrl()); + final String repositoryRelativeUrl = SvnUtil.ensureStartSlash(SvnUtil.join( + SvnUtil.getRelativeUrl(repositoryUrl.toDecodedString(), svnRootUrl.toDecodedString()), + SvnUtil.getRelativePath(rootUrlInfo.getPath(), file.getPath()))); FilePath filePath = VcsUtil.getFilePath(file); + SVNLogClient logger = myVcs.createLogClient(); - if (!tryExactHit(svnRootLocation, result, logger, revisionBefore, repositoryUrl, svnurl) && + if (!tryExactHit(svnRootLocation, result, logger, revisionBefore, repositoryUrl, svnRootUrl) && !tryByRoot(result, logger, revisionBefore, repositoryUrl)) { - filePath = getOneListStepByStep(svnRootLocation, result, logger, revisionBefore, svnurl, targetInfo, filePath); + filePath = + getOneListStepByStep(svnRootLocation, result, logger, revisionBefore, svnRootUrl, repositoryUrl, repositoryRelativeUrl, filePath); } else { Change change = ContainerUtil.getFirstItem(result[0].getChanges()); @@ -426,13 +402,10 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi filePath = afterRevision != null ? afterRevision.getFile() : filePath; } else { - String relativePath = SVNPathUtil.getRelativePath(targetInfo.getRepositoryRootURL().toString(), targetInfo.getURL().toString()); - relativePath = relativePath.startsWith("/") ? relativePath : "/" + relativePath; - final Change targetChange = result[0].getByPath(relativePath); + final Change targetChange = result[0].getByPath(repositoryRelativeUrl); - filePath = targetChange == null - ? getOneListStepByStep(svnRootLocation, result, logger, revisionBefore, svnurl, targetInfo, filePath) - : filePath; + filePath = targetChange == null ? getOneListStepByStep(svnRootLocation, result, logger, revisionBefore, svnRootUrl, repositoryUrl, + repositoryRelativeUrl, filePath) : filePath; } } @@ -444,8 +417,8 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi SVNLogClient logger, SVNRevision revisionBefore, SVNURL svnurl, - SVNInfo targetInfo, FilePath filePath) throws VcsException { - FilePath path = tryStepByStep(svnRootLocation, result, logger, revisionBefore, targetInfo, svnurl); + SVNURL repositoryUrl, String relativeUrl, FilePath filePath) throws VcsException { + FilePath path = tryStepByStep(svnRootLocation, result, logger, revisionBefore, repositoryUrl, relativeUrl, svnurl); return path == null ? filePath : path; } @@ -471,12 +444,12 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi // return changed path, if any private FilePath tryStepByStep(final SvnRepositoryLocation svnRepositoryLocation, - final SvnChangeList[] result, - SVNLogClient logger, - final SVNRevision revisionBefore, final SVNInfo info, SVNURL svnurl) throws VcsException { - final String repositoryRoot = info.getRepositoryRootURL().toString(); + final SvnChangeList[] result, + SVNLogClient logger, + final SVNRevision revisionBefore, final SVNURL repositoryUrl, String relativeUrl, SVNURL svnurl) + throws VcsException { try { - final SvnCopyPathTracker pathTracker = new SvnCopyPathTracker(info); + final SvnCopyPathTracker pathTracker = new SvnCopyPathTracker(repositoryUrl.toDecodedString(), relativeUrl); // TODO: Implement this with command line logger.doLog(svnurl, null, SVNRevision.UNDEFINED, SVNRevision.HEAD, revisionBefore, false, true, false, 0, null, @@ -489,7 +462,7 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi } pathTracker.accept(logEntry); if (logEntry.getRevision() == revisionBefore.getNumber()) { - result[0] = new SvnChangeList(myVcs, svnRepositoryLocation, logEntry, repositoryRoot); + result[0] = new SvnChangeList(myVcs, svnRepositoryLocation, logEntry, repositoryUrl.toDecodedString()); } } }); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCopyPathTracker.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCopyPathTracker.java index 93326dc3a108..70e982aeff8e 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCopyPathTracker.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCopyPathTracker.java @@ -25,7 +25,6 @@ import org.jetbrains.idea.svn.SvnVcs; import org.tmatesoft.svn.core.SVNLogEntry; import org.tmatesoft.svn.core.SVNLogEntryPath; import org.tmatesoft.svn.core.internal.util.SVNPathUtil; -import org.tmatesoft.svn.core.wc.SVNInfo; import java.io.File; import java.util.Map; @@ -41,10 +40,9 @@ public class SvnCopyPathTracker { private String myRepositoryRoot; private boolean myHadChanged; - public SvnCopyPathTracker(@NotNull final SVNInfo info) { - myRepositoryRoot = info.getRepositoryRootURL().toString(); - myCurrentPath = SVNPathUtil.getRelativePath(myRepositoryRoot, info.getURL().toString()); - myCurrentPath = myCurrentPath.startsWith("/") ? myCurrentPath : ("/" + myCurrentPath); + public SvnCopyPathTracker(@NotNull String repositoryUrl, @NotNull String relativeUrl) { + myRepositoryRoot = repositoryUrl; + myCurrentPath = relativeUrl; } public void accept(@NotNull final SVNLogEntry entry) { From a0363cba9906a6ac1a1f70ecddeabf12c8047814 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Thu, 6 Feb 2014 22:57:00 +0400 Subject: [PATCH 19/27] svn: Refactored SvnCommittedChangesProvider.getOneList - logic extracted to separate inner class --- .../history/SvnCommittedChangesProvider.java | 252 ++++++++++-------- 1 file changed, 139 insertions(+), 113 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java index 6620f3fe1774..65d70a22bc4c 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java @@ -374,53 +374,148 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi @Override public Pair getOneList(final VirtualFile file, VcsRevisionNumber number) throws VcsException { - final RootUrlInfo rootUrlInfo = myVcs.getSvnFileUrlMapping().getWcRootForFilePath(new File(file.getPath())); - if (rootUrlInfo == null) return null; - - final SvnChangeList[] result = new SvnChangeList[1]; - final SVNRevision revisionBefore = ((SvnRevisionNumber)number).getRevision(); - final SVNURL repositoryUrl = rootUrlInfo.getRepositoryUrlUrl(); - final SVNURL svnRootUrl = rootUrlInfo.getAbsoluteUrlAsUrl(); - final SvnRepositoryLocation svnRootLocation = new SvnRepositoryLocation(rootUrlInfo.getAbsoluteUrl()); - final String repositoryRelativeUrl = SvnUtil.ensureStartSlash(SvnUtil.join( - SvnUtil.getRelativeUrl(repositoryUrl.toDecodedString(), svnRootUrl.toDecodedString()), - SvnUtil.getRelativePath(rootUrlInfo.getPath(), file.getPath()))); - - FilePath filePath = VcsUtil.getFilePath(file); - SVNLogClient logger = myVcs.createLogClient(); - - if (!tryExactHit(svnRootLocation, result, logger, revisionBefore, repositoryUrl, svnRootUrl) && - !tryByRoot(result, logger, revisionBefore, repositoryUrl)) { - filePath = - getOneListStepByStep(svnRootLocation, result, logger, revisionBefore, svnRootUrl, repositoryUrl, repositoryRelativeUrl, filePath); - } - else { - Change change = ContainerUtil.getFirstItem(result[0].getChanges()); - if (change != null) { - final ContentRevision afterRevision = change.getAfterRevision(); - - filePath = afterRevision != null ? afterRevision.getFile() : filePath; - } - else { - final Change targetChange = result[0].getByPath(repositoryRelativeUrl); - - filePath = targetChange == null ? getOneListStepByStep(svnRootLocation, result, logger, revisionBefore, svnRootUrl, repositoryUrl, - repositoryRelativeUrl, filePath) : filePath; - } - } - - return Pair.create(result[0], filePath); + return new SingleCommittedListProvider(myVcs, file, number).run(); } - private FilePath getOneListStepByStep(SvnRepositoryLocation svnRootLocation, - SvnChangeList[] result, - SVNLogClient logger, - SVNRevision revisionBefore, - SVNURL svnurl, - SVNURL repositoryUrl, String relativeUrl, FilePath filePath) throws VcsException { - FilePath path = tryStepByStep(svnRootLocation, result, logger, revisionBefore, repositoryUrl, relativeUrl, svnurl); + private static class SingleCommittedListProvider { - return path == null ? filePath : path; + @NotNull private final SvnVcs myVcs; + @NotNull private final Project myProject; + @NotNull private final VirtualFile file; + @NotNull private final VcsRevisionNumber number; + private RootUrlInfo rootUrlInfo; + private SvnChangeList[] changeList; + private SVNRevision revisionBefore; + private SVNURL repositoryUrl; + private SVNURL svnRootUrl; + private SvnRepositoryLocation svnRootLocation; + private String repositoryRelativeUrl; + private FilePath filePath; + private SVNLogClient logger; + + private SingleCommittedListProvider(@NotNull SvnVcs vcs, @NotNull VirtualFile file, @NotNull VcsRevisionNumber number) { + myVcs = vcs; + myProject = vcs.getProject(); + this.file = file; + this.number = number; + } + + public Pair run() throws VcsException { + Pair result = null; + + if (setup()) { + calculate(); + result = Pair.create(changeList[0], filePath); + } + + return result; + } + + private boolean setup() { + boolean result = false; + + rootUrlInfo = myVcs.getSvnFileUrlMapping().getWcRootForFilePath(new File(file.getPath())); + if (rootUrlInfo != null) { + changeList = new SvnChangeList[1]; + revisionBefore = ((SvnRevisionNumber)number).getRevision(); + repositoryUrl = rootUrlInfo.getRepositoryUrlUrl(); + svnRootUrl = rootUrlInfo.getAbsoluteUrlAsUrl(); + svnRootLocation = new SvnRepositoryLocation(rootUrlInfo.getAbsoluteUrl()); + repositoryRelativeUrl = SvnUtil.ensureStartSlash(SvnUtil.join( + SvnUtil.getRelativeUrl(repositoryUrl.toDecodedString(), svnRootUrl.toDecodedString()), + SvnUtil.getRelativePath(rootUrlInfo.getPath(), file.getPath()))); + + filePath = VcsUtil.getFilePath(file); + logger = myVcs.createLogClient(); + + result = true; + } + + return result; + } + + private void calculate() throws VcsException { + if (!tryExactHit(svnRootUrl) && !tryByRoot(repositoryUrl)) { + filePath = getOneListStepByStep(svnRootUrl); + } + else { + Change change = ContainerUtil.getFirstItem(changeList[0].getChanges()); + if (change != null) { + final ContentRevision afterRevision = change.getAfterRevision(); + + filePath = afterRevision != null ? afterRevision.getFile() : filePath; + } + else { + final Change targetChange = changeList[0].getByPath(repositoryRelativeUrl); + + filePath = targetChange == null ? getOneListStepByStep(svnRootUrl) : filePath; + } + } + } + + private FilePath getOneListStepByStep(SVNURL svnurl) throws VcsException { + FilePath path = tryStepByStep(svnurl); + + return path == null ? filePath : path; + } + + private boolean tryByRoot(SVNURL repositoryUrl) throws VcsException { + final boolean authorized = SvnAuthenticationNotifier.passiveValidation(myProject, repositoryUrl); + + return authorized && tryExactHit(repositoryUrl); + } + + // return changed path, if any + private FilePath tryStepByStep(SVNURL svnurl) throws VcsException { + try { + final SvnCopyPathTracker pathTracker = new SvnCopyPathTracker(repositoryUrl.toDecodedString(), repositoryRelativeUrl); + // TODO: Implement this with command line + logger.doLog(svnurl, null, SVNRevision.UNDEFINED, SVNRevision.HEAD, revisionBefore, + false, true, false, 0, null, + new ISVNLogEntryHandler() { + public void handleLogEntry(SVNLogEntry logEntry) { + if (myProject.isDisposed()) throw new ProcessCanceledException(); + if (logEntry.getDate() == null) { + // do not add lists without info - this situation is possible for lists where there are paths that user has no rights to observe + return; + } + pathTracker.accept(logEntry); + if (logEntry.getRevision() == revisionBefore.getNumber()) { + changeList[0] = new SvnChangeList(myVcs, svnRootLocation, logEntry, repositoryUrl.toDecodedString()); + } + } + }); + return pathTracker.getFilePath(myVcs); + } + catch (SVNException e) { + LOG.info(e); + throw new VcsException(e); + } + } + + private boolean tryExactHit(SVNURL svnurl) throws VcsException { + ISVNLogEntryHandler handler = new ISVNLogEntryHandler() { + public void handleLogEntry(SVNLogEntry logEntry) { + if (myProject.isDisposed()) throw new ProcessCanceledException(); + if (logEntry.getDate() == null) { + // do not add lists without info - this situation is possible for lists where there are paths that user has no rights to observe + return; + } + changeList[0] = new SvnChangeList(myVcs, svnRootLocation, logEntry, repositoryUrl.toString()); + } + }; + try { + // TODO: Implement this with command line + logger.doLog(svnurl, null, SVNRevision.UNDEFINED, revisionBefore, revisionBefore, false, true, false, 1, null, handler); + } + catch (SVNException e) { + LOG.info(e); + if (SVNErrorCode.FS_CATEGORY != e.getErrorMessage().getErrorCode().getCategory()) { + throw new VcsException(e); + } + } + return changeList[0] != null; + } } @Override @@ -434,75 +529,6 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi return true; } - private boolean tryByRoot(SvnChangeList[] result, SVNLogClient logger, SVNRevision revisionBefore, SVNURL repositoryUrl) - throws VcsException { - final boolean authorized = SvnAuthenticationNotifier.passiveValidation(myProject, repositoryUrl); - - return authorized && - tryExactHit(new SvnRepositoryLocation(repositoryUrl.toString()), result, logger, revisionBefore, repositoryUrl, repositoryUrl); - } - - // return changed path, if any - private FilePath tryStepByStep(final SvnRepositoryLocation svnRepositoryLocation, - final SvnChangeList[] result, - SVNLogClient logger, - final SVNRevision revisionBefore, final SVNURL repositoryUrl, String relativeUrl, SVNURL svnurl) - throws VcsException { - try { - final SvnCopyPathTracker pathTracker = new SvnCopyPathTracker(repositoryUrl.toDecodedString(), relativeUrl); - // TODO: Implement this with command line - logger.doLog(svnurl, null, SVNRevision.UNDEFINED, SVNRevision.HEAD, revisionBefore, - false, true, false, 0, null, - new ISVNLogEntryHandler() { - public void handleLogEntry(SVNLogEntry logEntry) { - if (myProject.isDisposed()) throw new ProcessCanceledException(); - if (logEntry.getDate() == null) { - // do not add lists without info - this situation is possible for lists where there are paths that user has no rights to observe - return; - } - pathTracker.accept(logEntry); - if (logEntry.getRevision() == revisionBefore.getNumber()) { - result[0] = new SvnChangeList(myVcs, svnRepositoryLocation, logEntry, repositoryUrl.toDecodedString()); - } - } - }); - return pathTracker.getFilePath(myVcs); - } - catch (SVNException e) { - LOG.info(e); - throw new VcsException(e); - } - } - - private boolean tryExactHit(final SvnRepositoryLocation location, - final SvnChangeList[] result, - SVNLogClient logger, - SVNRevision revisionBefore, - final SVNURL repositoryUrl, SVNURL svnurl) throws VcsException { - - ISVNLogEntryHandler handler = new ISVNLogEntryHandler() { - public void handleLogEntry(SVNLogEntry logEntry) { - if (myProject.isDisposed()) throw new ProcessCanceledException(); - if (logEntry.getDate() == null) { - // do not add lists without info - this situation is possible for lists where there are paths that user has no rights to observe - return; - } - result[0] = new SvnChangeList(myVcs, location, logEntry, repositoryUrl.toString()); - } - }; - try { - // TODO: Implement this with command line - logger.doLog(svnurl, null, SVNRevision.UNDEFINED, revisionBefore, revisionBefore, false, true, false, 1, null, handler); - } - catch (SVNException e) { - LOG.info(e); - if (SVNErrorCode.FS_CATEGORY != e.getErrorMessage().getErrorCode().getCategory()) { - throw new VcsException(e); - } - } - return result[0] != null; - } - public int getFormatVersion() { return VERSION_WITH_REPLACED_PATHS; } From 80dedd3039794fa794daa1c3a59ad0a65f7e7896 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Thu, 6 Feb 2014 23:00:29 +0400 Subject: [PATCH 20/27] svn: Refactored SvnCommittedChangesProvider - SingleCommittedListProvider extracted to separate class --- .../history/SingleCommittedListProvider.java | 182 ++++++++++++++++++ .../history/SvnCommittedChangesProvider.java | 149 -------------- 2 files changed, 182 insertions(+), 149 deletions(-) create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/history/SingleCommittedListProvider.java diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SingleCommittedListProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SingleCommittedListProvider.java new file mode 100644 index 000000000000..71a437b3fad9 --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SingleCommittedListProvider.java @@ -0,0 +1,182 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.idea.svn.history; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.vcs.FilePath; +import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vcs.changes.Change; +import com.intellij.openapi.vcs.changes.ContentRevision; +import com.intellij.openapi.vcs.history.VcsRevisionNumber; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.vcsUtil.VcsUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.svn.*; +import org.tmatesoft.svn.core.*; +import org.tmatesoft.svn.core.wc.SVNLogClient; +import org.tmatesoft.svn.core.wc.SVNRevision; + +import java.io.File; + +/** +* @author Konstantin Kolosovsky. +*/ +public class SingleCommittedListProvider { + + private static final Logger LOG = Logger.getInstance(SingleCommittedListProvider.class); + + @NotNull private final SvnVcs myVcs; + @NotNull private final Project myProject; + @NotNull private final VirtualFile file; + @NotNull private final VcsRevisionNumber number; + private RootUrlInfo rootUrlInfo; + private SvnChangeList[] changeList; + private SVNRevision revisionBefore; + private SVNURL repositoryUrl; + private SVNURL svnRootUrl; + private SvnRepositoryLocation svnRootLocation; + private String repositoryRelativeUrl; + private FilePath filePath; + private SVNLogClient logger; + + SingleCommittedListProvider(@NotNull SvnVcs vcs, @NotNull VirtualFile file, @NotNull VcsRevisionNumber number) { + myVcs = vcs; + myProject = vcs.getProject(); + this.file = file; + this.number = number; + } + + public Pair run() throws VcsException { + Pair result = null; + + if (setup()) { + calculate(); + result = Pair.create(changeList[0], filePath); + } + + return result; + } + + private boolean setup() { + boolean result = false; + + rootUrlInfo = myVcs.getSvnFileUrlMapping().getWcRootForFilePath(new File(file.getPath())); + if (rootUrlInfo != null) { + changeList = new SvnChangeList[1]; + revisionBefore = ((SvnRevisionNumber)number).getRevision(); + repositoryUrl = rootUrlInfo.getRepositoryUrlUrl(); + svnRootUrl = rootUrlInfo.getAbsoluteUrlAsUrl(); + svnRootLocation = new SvnRepositoryLocation(rootUrlInfo.getAbsoluteUrl()); + repositoryRelativeUrl = SvnUtil.ensureStartSlash(SvnUtil.join( + SvnUtil.getRelativeUrl(repositoryUrl.toDecodedString(), svnRootUrl.toDecodedString()), + SvnUtil.getRelativePath(rootUrlInfo.getPath(), file.getPath()))); + + filePath = VcsUtil.getFilePath(file); + logger = myVcs.createLogClient(); + + result = true; + } + + return result; + } + + private void calculate() throws VcsException { + if (!tryExactHit(svnRootUrl) && !tryByRoot(repositoryUrl)) { + filePath = getOneListStepByStep(svnRootUrl); + } + else { + Change change = ContainerUtil.getFirstItem(changeList[0].getChanges()); + if (change != null) { + final ContentRevision afterRevision = change.getAfterRevision(); + + filePath = afterRevision != null ? afterRevision.getFile() : filePath; + } + else { + final Change targetChange = changeList[0].getByPath(repositoryRelativeUrl); + + filePath = targetChange == null ? getOneListStepByStep(svnRootUrl) : filePath; + } + } + } + + private FilePath getOneListStepByStep(SVNURL svnurl) throws VcsException { + FilePath path = tryStepByStep(svnurl); + + return path == null ? filePath : path; + } + + private boolean tryByRoot(SVNURL repositoryUrl) throws VcsException { + final boolean authorized = SvnAuthenticationNotifier.passiveValidation(myProject, repositoryUrl); + + return authorized && tryExactHit(repositoryUrl); + } + + // return changed path, if any + private FilePath tryStepByStep(SVNURL svnurl) throws VcsException { + try { + final SvnCopyPathTracker pathTracker = new SvnCopyPathTracker(repositoryUrl.toDecodedString(), repositoryRelativeUrl); + // TODO: Implement this with command line + logger.doLog(svnurl, null, SVNRevision.UNDEFINED, SVNRevision.HEAD, revisionBefore, + false, true, false, 0, null, + new ISVNLogEntryHandler() { + public void handleLogEntry(SVNLogEntry logEntry) { + if (myProject.isDisposed()) throw new ProcessCanceledException(); + if (logEntry.getDate() == null) { + // do not add lists without info - this situation is possible for lists where there are paths that user has no rights to observe + return; + } + pathTracker.accept(logEntry); + if (logEntry.getRevision() == revisionBefore.getNumber()) { + changeList[0] = new SvnChangeList(myVcs, svnRootLocation, logEntry, repositoryUrl.toDecodedString()); + } + } + }); + return pathTracker.getFilePath(myVcs); + } + catch (SVNException e) { + LOG.info(e); + throw new VcsException(e); + } + } + + private boolean tryExactHit(SVNURL svnurl) throws VcsException { + ISVNLogEntryHandler handler = new ISVNLogEntryHandler() { + public void handleLogEntry(SVNLogEntry logEntry) { + if (myProject.isDisposed()) throw new ProcessCanceledException(); + if (logEntry.getDate() == null) { + // do not add lists without info - this situation is possible for lists where there are paths that user has no rights to observe + return; + } + changeList[0] = new SvnChangeList(myVcs, svnRootLocation, logEntry, repositoryUrl.toString()); + } + }; + try { + // TODO: Implement this with command line + logger.doLog(svnurl, null, SVNRevision.UNDEFINED, revisionBefore, revisionBefore, false, true, false, 1, null, handler); + } + catch (SVNException e) { + LOG.info(e); + if (SVNErrorCode.FS_CATEGORY != e.getErrorMessage().getErrorCode().getCategory()) { + throw new VcsException(e); + } + } + return changeList[0] != null; + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java index 65d70a22bc4c..f8b0717502ac 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java @@ -19,7 +19,6 @@ package org.jetbrains.idea.svn.history; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; @@ -27,8 +26,6 @@ import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.ThrowableComputable; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vcs.*; -import com.intellij.openapi.vcs.changes.Change; -import com.intellij.openapi.vcs.changes.ContentRevision; import com.intellij.openapi.vcs.changes.committed.DecoratorManager; import com.intellij.openapi.vcs.changes.committed.VcsCommittedListsZipper; import com.intellij.openapi.vcs.changes.committed.VcsCommittedViewAuxiliary; @@ -42,9 +39,7 @@ import com.intellij.util.AsynchConsumer; import com.intellij.util.Consumer; import com.intellij.util.PairConsumer; import com.intellij.util.ThrowableConsumer; -import com.intellij.util.containers.ContainerUtil; import com.intellij.util.messages.MessageBusConnection; -import com.intellij.vcsUtil.VcsUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.*; @@ -57,7 +52,6 @@ import org.tmatesoft.svn.core.wc.SVNRevision; import java.io.DataInput; import java.io.DataOutput; -import java.io.File; import java.io.IOException; import java.util.*; @@ -74,8 +68,6 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi public final static int VERSION_WITH_COPY_PATHS_ADDED = 2; public final static int VERSION_WITH_REPLACED_PATHS = 3; - private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.history.SvnCommittedChangesProvider"); - public SvnCommittedChangesProvider(final Project project) { myProject = project; myVcs = SvnVcs.getInstance(myProject); @@ -377,147 +369,6 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi return new SingleCommittedListProvider(myVcs, file, number).run(); } - private static class SingleCommittedListProvider { - - @NotNull private final SvnVcs myVcs; - @NotNull private final Project myProject; - @NotNull private final VirtualFile file; - @NotNull private final VcsRevisionNumber number; - private RootUrlInfo rootUrlInfo; - private SvnChangeList[] changeList; - private SVNRevision revisionBefore; - private SVNURL repositoryUrl; - private SVNURL svnRootUrl; - private SvnRepositoryLocation svnRootLocation; - private String repositoryRelativeUrl; - private FilePath filePath; - private SVNLogClient logger; - - private SingleCommittedListProvider(@NotNull SvnVcs vcs, @NotNull VirtualFile file, @NotNull VcsRevisionNumber number) { - myVcs = vcs; - myProject = vcs.getProject(); - this.file = file; - this.number = number; - } - - public Pair run() throws VcsException { - Pair result = null; - - if (setup()) { - calculate(); - result = Pair.create(changeList[0], filePath); - } - - return result; - } - - private boolean setup() { - boolean result = false; - - rootUrlInfo = myVcs.getSvnFileUrlMapping().getWcRootForFilePath(new File(file.getPath())); - if (rootUrlInfo != null) { - changeList = new SvnChangeList[1]; - revisionBefore = ((SvnRevisionNumber)number).getRevision(); - repositoryUrl = rootUrlInfo.getRepositoryUrlUrl(); - svnRootUrl = rootUrlInfo.getAbsoluteUrlAsUrl(); - svnRootLocation = new SvnRepositoryLocation(rootUrlInfo.getAbsoluteUrl()); - repositoryRelativeUrl = SvnUtil.ensureStartSlash(SvnUtil.join( - SvnUtil.getRelativeUrl(repositoryUrl.toDecodedString(), svnRootUrl.toDecodedString()), - SvnUtil.getRelativePath(rootUrlInfo.getPath(), file.getPath()))); - - filePath = VcsUtil.getFilePath(file); - logger = myVcs.createLogClient(); - - result = true; - } - - return result; - } - - private void calculate() throws VcsException { - if (!tryExactHit(svnRootUrl) && !tryByRoot(repositoryUrl)) { - filePath = getOneListStepByStep(svnRootUrl); - } - else { - Change change = ContainerUtil.getFirstItem(changeList[0].getChanges()); - if (change != null) { - final ContentRevision afterRevision = change.getAfterRevision(); - - filePath = afterRevision != null ? afterRevision.getFile() : filePath; - } - else { - final Change targetChange = changeList[0].getByPath(repositoryRelativeUrl); - - filePath = targetChange == null ? getOneListStepByStep(svnRootUrl) : filePath; - } - } - } - - private FilePath getOneListStepByStep(SVNURL svnurl) throws VcsException { - FilePath path = tryStepByStep(svnurl); - - return path == null ? filePath : path; - } - - private boolean tryByRoot(SVNURL repositoryUrl) throws VcsException { - final boolean authorized = SvnAuthenticationNotifier.passiveValidation(myProject, repositoryUrl); - - return authorized && tryExactHit(repositoryUrl); - } - - // return changed path, if any - private FilePath tryStepByStep(SVNURL svnurl) throws VcsException { - try { - final SvnCopyPathTracker pathTracker = new SvnCopyPathTracker(repositoryUrl.toDecodedString(), repositoryRelativeUrl); - // TODO: Implement this with command line - logger.doLog(svnurl, null, SVNRevision.UNDEFINED, SVNRevision.HEAD, revisionBefore, - false, true, false, 0, null, - new ISVNLogEntryHandler() { - public void handleLogEntry(SVNLogEntry logEntry) { - if (myProject.isDisposed()) throw new ProcessCanceledException(); - if (logEntry.getDate() == null) { - // do not add lists without info - this situation is possible for lists where there are paths that user has no rights to observe - return; - } - pathTracker.accept(logEntry); - if (logEntry.getRevision() == revisionBefore.getNumber()) { - changeList[0] = new SvnChangeList(myVcs, svnRootLocation, logEntry, repositoryUrl.toDecodedString()); - } - } - }); - return pathTracker.getFilePath(myVcs); - } - catch (SVNException e) { - LOG.info(e); - throw new VcsException(e); - } - } - - private boolean tryExactHit(SVNURL svnurl) throws VcsException { - ISVNLogEntryHandler handler = new ISVNLogEntryHandler() { - public void handleLogEntry(SVNLogEntry logEntry) { - if (myProject.isDisposed()) throw new ProcessCanceledException(); - if (logEntry.getDate() == null) { - // do not add lists without info - this situation is possible for lists where there are paths that user has no rights to observe - return; - } - changeList[0] = new SvnChangeList(myVcs, svnRootLocation, logEntry, repositoryUrl.toString()); - } - }; - try { - // TODO: Implement this with command line - logger.doLog(svnurl, null, SVNRevision.UNDEFINED, revisionBefore, revisionBefore, false, true, false, 1, null, handler); - } - catch (SVNException e) { - LOG.info(e); - if (SVNErrorCode.FS_CATEGORY != e.getErrorMessage().getErrorCode().getCategory()) { - throw new VcsException(e); - } - } - return changeList[0] != null; - } - } - @Override public RepositoryLocation getForNonLocal(VirtualFile file) { final String url = file.getPresentableUrl(); From 27794a5278ab54f3d9129179c376143187bc600c Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Mon, 10 Feb 2014 14:06:06 +0400 Subject: [PATCH 21/27] svn: Fixed SingleCommittedListProvider - use previous logic to check changes size and not just first item --- .../idea/svn/history/SingleCommittedListProvider.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SingleCommittedListProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SingleCommittedListProvider.java index 71a437b3fad9..97f69509c1ff 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SingleCommittedListProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SingleCommittedListProvider.java @@ -102,9 +102,8 @@ public class SingleCommittedListProvider { filePath = getOneListStepByStep(svnRootUrl); } else { - Change change = ContainerUtil.getFirstItem(changeList[0].getChanges()); - if (change != null) { - final ContentRevision afterRevision = change.getAfterRevision(); + if (changeList[0].getChanges().size() == 1) { + final ContentRevision afterRevision = changeList[0].getChanges().iterator().next().getAfterRevision(); filePath = afterRevision != null ? afterRevision.getFile() : filePath; } From 7f04cc28f84267eee4033eed4b468bd536eb34cf Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Mon, 10 Feb 2014 14:19:31 +0400 Subject: [PATCH 22/27] svn: Refactored SingleCommittedListProvider - renames, removed duplication --- .../history/SingleCommittedListProvider.java | 71 ++++++++++--------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SingleCommittedListProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SingleCommittedListProvider.java index 97f69509c1ff..e15bf2650daf 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SingleCommittedListProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SingleCommittedListProvider.java @@ -25,7 +25,6 @@ import com.intellij.openapi.vcs.changes.Change; import com.intellij.openapi.vcs.changes.ContentRevision; import com.intellij.openapi.vcs.history.VcsRevisionNumber; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.containers.ContainerUtil; import com.intellij.vcsUtil.VcsUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.*; @@ -46,7 +45,6 @@ public class SingleCommittedListProvider { @NotNull private final Project myProject; @NotNull private final VirtualFile file; @NotNull private final VcsRevisionNumber number; - private RootUrlInfo rootUrlInfo; private SvnChangeList[] changeList; private SVNRevision revisionBefore; private SVNURL repositoryUrl; @@ -56,7 +54,7 @@ public class SingleCommittedListProvider { private FilePath filePath; private SVNLogClient logger; - SingleCommittedListProvider(@NotNull SvnVcs vcs, @NotNull VirtualFile file, @NotNull VcsRevisionNumber number) { + public SingleCommittedListProvider(@NotNull SvnVcs vcs, @NotNull VirtualFile file, @NotNull VcsRevisionNumber number) { myVcs = vcs; myProject = vcs.getProject(); this.file = file; @@ -77,7 +75,7 @@ public class SingleCommittedListProvider { private boolean setup() { boolean result = false; - rootUrlInfo = myVcs.getSvnFileUrlMapping().getWcRootForFilePath(new File(file.getPath())); + RootUrlInfo rootUrlInfo = myVcs.getSvnFileUrlMapping().getWcRootForFilePath(new File(file.getPath())); if (rootUrlInfo != null) { changeList = new SvnChangeList[1]; revisionBefore = ((SvnRevisionNumber)number).getRevision(); @@ -98,8 +96,8 @@ public class SingleCommittedListProvider { } private void calculate() throws VcsException { - if (!tryExactHit(svnRootUrl) && !tryByRoot(repositoryUrl)) { - filePath = getOneListStepByStep(svnRootUrl); + if (!searchForUrl(svnRootUrl) && !(hasAccess(repositoryUrl) && searchForUrl(repositoryUrl))) { + filePath = searchFromHead(svnRootUrl); } else { if (changeList[0].getChanges().size() == 1) { @@ -110,44 +108,37 @@ public class SingleCommittedListProvider { else { final Change targetChange = changeList[0].getByPath(repositoryRelativeUrl); - filePath = targetChange == null ? getOneListStepByStep(svnRootUrl) : filePath; + filePath = targetChange == null ? searchFromHead(svnRootUrl) : filePath; } } } - private FilePath getOneListStepByStep(SVNURL svnurl) throws VcsException { - FilePath path = tryStepByStep(svnurl); - - return path == null ? filePath : path; - } - - private boolean tryByRoot(SVNURL repositoryUrl) throws VcsException { - final boolean authorized = SvnAuthenticationNotifier.passiveValidation(myProject, repositoryUrl); - - return authorized && tryExactHit(repositoryUrl); + private boolean hasAccess(@NotNull SVNURL url) { + return SvnAuthenticationNotifier.passiveValidation(myProject, url); } // return changed path, if any - private FilePath tryStepByStep(SVNURL svnurl) throws VcsException { + private FilePath searchFromHead(@NotNull SVNURL url) throws VcsException { try { final SvnCopyPathTracker pathTracker = new SvnCopyPathTracker(repositoryUrl.toDecodedString(), repositoryRelativeUrl); // TODO: Implement this with command line - logger.doLog(svnurl, null, SVNRevision.UNDEFINED, SVNRevision.HEAD, revisionBefore, + logger.doLog(url, null, SVNRevision.UNDEFINED, SVNRevision.HEAD, revisionBefore, false, true, false, 0, null, new ISVNLogEntryHandler() { public void handleLogEntry(SVNLogEntry logEntry) { - if (myProject.isDisposed()) throw new ProcessCanceledException(); - if (logEntry.getDate() == null) { - // do not add lists without info - this situation is possible for lists where there are paths that user has no rights to observe - return; - } - pathTracker.accept(logEntry); - if (logEntry.getRevision() == revisionBefore.getNumber()) { - changeList[0] = new SvnChangeList(myVcs, svnRootLocation, logEntry, repositoryUrl.toDecodedString()); + checkDisposed(); + // date could be null for lists where there are paths that user has no rights to observe + if (logEntry.getDate() != null) { + pathTracker.accept(logEntry); + if (logEntry.getRevision() == revisionBefore.getNumber()) { + changeList[0] = createChangeList(logEntry); + } } } }); - return pathTracker.getFilePath(myVcs); + + FilePath path = pathTracker.getFilePath(myVcs); + return path == null ? filePath : path; } catch (SVNException e) { LOG.info(e); @@ -155,20 +146,30 @@ public class SingleCommittedListProvider { } } - private boolean tryExactHit(SVNURL svnurl) throws VcsException { + @NotNull + private SvnChangeList createChangeList(@NotNull SVNLogEntry logEntry) { + return new SvnChangeList(myVcs, svnRootLocation, logEntry, repositoryUrl.toDecodedString()); + } + + private void checkDisposed() { + if (myProject.isDisposed()) { + throw new ProcessCanceledException(); + } + } + + private boolean searchForUrl(@NotNull SVNURL url) throws VcsException { ISVNLogEntryHandler handler = new ISVNLogEntryHandler() { public void handleLogEntry(SVNLogEntry logEntry) { - if (myProject.isDisposed()) throw new ProcessCanceledException(); - if (logEntry.getDate() == null) { - // do not add lists without info - this situation is possible for lists where there are paths that user has no rights to observe - return; + checkDisposed(); + // date could be null for lists where there are paths that user has no rights to observe + if (logEntry.getDate() != null) { + changeList[0] = createChangeList(logEntry); } - changeList[0] = new SvnChangeList(myVcs, svnRootLocation, logEntry, repositoryUrl.toString()); } }; try { // TODO: Implement this with command line - logger.doLog(svnurl, null, SVNRevision.UNDEFINED, revisionBefore, revisionBefore, false, true, false, 1, null, handler); + logger.doLog(url, null, SVNRevision.UNDEFINED, revisionBefore, revisionBefore, false, true, false, 1, null, handler); } catch (SVNException e) { LOG.info(e); From d7df2d4b336e0b5ccb9a3f2578de86f855399e94 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Mon, 10 Feb 2014 16:23:42 +0400 Subject: [PATCH 23/27] svn: Implemented command line support for SingleCommittedListProvider --- .../svn/commandLine/SvnBindException.java | 20 ++++++ .../idea/svn/history/CmdHistoryClient.java | 8 +-- .../history/SingleCommittedListProvider.java | 61 +++++++++---------- .../idea/svn/history/SvnKitHistoryClient.java | 3 +- 4 files changed, 54 insertions(+), 38 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnBindException.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnBindException.java index bcfcba50b87a..1976a31e311d 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnBindException.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnBindException.java @@ -15,9 +15,11 @@ */ package org.jetbrains.idea.svn.commandLine; +import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.VcsException; import com.intellij.util.LineSeparator; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.hash.HashMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -38,6 +40,9 @@ import java.util.regex.Matcher; */ public class SvnBindException extends VcsException { + public static final int ERROR_BASE = 120000; + public static final int CATEGORY_SIZE = 5000; + private Map errors = new HashMap(); public SvnBindException(String message) { @@ -67,6 +72,21 @@ public class SvnBindException extends VcsException { return errors.containsKey(error.getCode()); } + public boolean containsCategory(int category) { + final int categoryCode = getCategoryCode(category); + + return ContainerUtil.exists(errors.keySet(), new Condition() { + @Override + public boolean value(Integer code) { + return getCategoryCode(code) == categoryCode; + } + }); + } + + private static int getCategoryCode(int category) { + return (category - ERROR_BASE) / CATEGORY_SIZE; + } + private void parseErrors(@NotNull String message) { Matcher matcher = SvnUtil.ERROR_PATTERN.matcher(message); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/CmdHistoryClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/CmdHistoryClient.java index a044fedf9678..567c21f694e6 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/CmdHistoryClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/CmdHistoryClient.java @@ -7,11 +7,9 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.api.BaseSvnClient; import org.jetbrains.idea.svn.commandLine.CommandExecutor; import org.jetbrains.idea.svn.commandLine.CommandUtil; +import org.jetbrains.idea.svn.commandLine.SvnBindException; import org.jetbrains.idea.svn.commandLine.SvnCommandName; -import org.tmatesoft.svn.core.ISVNLogEntryHandler; -import org.tmatesoft.svn.core.SVNException; -import org.tmatesoft.svn.core.SVNLogEntry; -import org.tmatesoft.svn.core.SVNLogEntryPath; +import org.tmatesoft.svn.core.*; import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc2.SvnTarget; @@ -52,7 +50,7 @@ public class CmdHistoryClient extends BaseSvnClient implements HistoryClient { parseOutput(command, handler); } catch (SVNException e) { - throw new VcsException(e); + throw new SvnBindException(e); } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SingleCommittedListProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SingleCommittedListProvider.java index e15bf2650daf..e62b8e041623 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SingleCommittedListProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SingleCommittedListProvider.java @@ -28,9 +28,10 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.vcsUtil.VcsUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.*; +import org.jetbrains.idea.svn.commandLine.SvnBindException; import org.tmatesoft.svn.core.*; -import org.tmatesoft.svn.core.wc.SVNLogClient; import org.tmatesoft.svn.core.wc.SVNRevision; +import org.tmatesoft.svn.core.wc2.SvnTarget; import java.io.File; @@ -52,7 +53,6 @@ public class SingleCommittedListProvider { private SvnRepositoryLocation svnRootLocation; private String repositoryRelativeUrl; private FilePath filePath; - private SVNLogClient logger; public SingleCommittedListProvider(@NotNull SvnVcs vcs, @NotNull VirtualFile file, @NotNull VcsRevisionNumber number) { myVcs = vcs; @@ -87,7 +87,6 @@ public class SingleCommittedListProvider { SvnUtil.getRelativePath(rootUrlInfo.getPath(), file.getPath()))); filePath = VcsUtil.getFilePath(file); - logger = myVcs.createLogClient(); result = true; } @@ -96,6 +95,8 @@ public class SingleCommittedListProvider { } private void calculate() throws VcsException { + // TODO: Seems that filePath detection could be replaced with "svn info -r " - and not call + // TODO: "svn log -r HEAD:" and track copies manually (which also is not correct for all cases). if (!searchForUrl(svnRootUrl) && !(hasAccess(repositoryUrl) && searchForUrl(repositoryUrl))) { filePath = searchFromHead(svnRootUrl); } @@ -119,31 +120,26 @@ public class SingleCommittedListProvider { // return changed path, if any private FilePath searchFromHead(@NotNull SVNURL url) throws VcsException { - try { - final SvnCopyPathTracker pathTracker = new SvnCopyPathTracker(repositoryUrl.toDecodedString(), repositoryRelativeUrl); - // TODO: Implement this with command line - logger.doLog(url, null, SVNRevision.UNDEFINED, SVNRevision.HEAD, revisionBefore, - false, true, false, 0, null, - new ISVNLogEntryHandler() { - public void handleLogEntry(SVNLogEntry logEntry) { - checkDisposed(); - // date could be null for lists where there are paths that user has no rights to observe - if (logEntry.getDate() != null) { - pathTracker.accept(logEntry); - if (logEntry.getRevision() == revisionBefore.getNumber()) { - changeList[0] = createChangeList(logEntry); - } - } - } - }); + final SvnCopyPathTracker pathTracker = new SvnCopyPathTracker(repositoryUrl.toDecodedString(), repositoryRelativeUrl); + SvnTarget target = SvnTarget.fromURL(url); - FilePath path = pathTracker.getFilePath(myVcs); - return path == null ? filePath : path; - } - catch (SVNException e) { - LOG.info(e); - throw new VcsException(e); - } + myVcs.getFactory(target).createHistoryClient().doLog(target, SVNRevision.HEAD, revisionBefore, false, true, false, 0, null, + new ISVNLogEntryHandler() { + public void handleLogEntry(SVNLogEntry logEntry) { + checkDisposed(); + // date could be null for lists where there are paths that user has no rights to observe + if (logEntry.getDate() != null) { + pathTracker.accept(logEntry); + if (logEntry.getRevision() == revisionBefore.getNumber()) { + changeList[0] = createChangeList(logEntry); + } + } + } + } + ); + + FilePath path = pathTracker.getFilePath(myVcs); + return path == null ? filePath : path; } @NotNull @@ -167,14 +163,15 @@ public class SingleCommittedListProvider { } } }; + + SvnTarget target = SvnTarget.fromURL(url); try { - // TODO: Implement this with command line - logger.doLog(url, null, SVNRevision.UNDEFINED, revisionBefore, revisionBefore, false, true, false, 1, null, handler); + myVcs.getFactory(target).createHistoryClient().doLog(target, revisionBefore, revisionBefore, false, true, false, 1, null, handler); } - catch (SVNException e) { + catch (SvnBindException e) { LOG.info(e); - if (SVNErrorCode.FS_CATEGORY != e.getErrorMessage().getErrorCode().getCategory()) { - throw new VcsException(e); + if (!e.containsCategory(SVNErrorCode.FS_CATEGORY)) { + throw e; } } return changeList[0] != null; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnKitHistoryClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnKitHistoryClient.java index bf97f21b809a..f58e6c8f542f 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnKitHistoryClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnKitHistoryClient.java @@ -5,6 +5,7 @@ import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.api.BaseSvnClient; +import org.jetbrains.idea.svn.commandLine.SvnBindException; import org.tmatesoft.svn.core.ISVNLogEntryHandler; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.wc.SVNLogClient; @@ -42,7 +43,7 @@ public class SvnKitHistoryClient extends BaseSvnClient implements HistoryClient } } catch (SVNException e) { - throw new VcsException(e); + throw new SvnBindException(e); } } } From 353d5579c20b06f46999cc6d8688ae7c5b183b97 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Mon, 10 Feb 2014 17:06:47 +0400 Subject: [PATCH 24/27] IDEA-118646 Determine client factory for "revert" operation based on file being reverted (and not only based on project root and settings) --- .../idea/svn/rollback/SvnRollbackEnvironment.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/rollback/SvnRollbackEnvironment.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/rollback/SvnRollbackEnvironment.java index ed097b42a85a..488eed44ab2f 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/rollback/SvnRollbackEnvironment.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/rollback/SvnRollbackEnvironment.java @@ -28,7 +28,6 @@ import com.intellij.util.containers.MultiMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.*; -import org.jetbrains.idea.svn.revert.RevertClient; import org.tmatesoft.svn.core.*; import org.tmatesoft.svn.core.wc.*; @@ -99,7 +98,7 @@ public class SvnRollbackEnvironment extends DefaultRollbackEnvironment { // adds (deletes) // deletes (adds) // modifications - final Reverter reverter = new Reverter(mySvnVcs.getFactory().createRevertClient(), revertHandler, exceptions); + final Reverter reverter = new Reverter(mySvnVcs, revertHandler, exceptions); reverter.revert(checker.getForAdds(), true); reverter.revert(checker.getForDeletes(), true); final List edits = checker.getForEdits(); @@ -256,12 +255,12 @@ public class SvnRollbackEnvironment extends DefaultRollbackEnvironment { } private static class Reverter { - private final RevertClient myClient; + @NotNull private final SvnVcs myVcs; private ISVNEventHandler myHandler; private final List myExceptions; - private Reverter(RevertClient client, ISVNEventHandler handler, List exceptions) { - myClient = client; + private Reverter(@NotNull SvnVcs vcs, ISVNEventHandler handler, List exceptions) { + myVcs = vcs; myHandler = handler; myExceptions = exceptions; } @@ -269,7 +268,8 @@ public class SvnRollbackEnvironment extends DefaultRollbackEnvironment { public void revert(final File[] files, final boolean recursive) { if (files.length == 0) return; try { - myClient.revert(files, recursive ? SVNDepth.INFINITY : SVNDepth.EMPTY, myHandler); + // Files passed here are split into groups by root and working copy format - thus we could determine factory based on first file + myVcs.getFactory(files[0]).createRevertClient().revert(files, recursive ? SVNDepth.INFINITY : SVNDepth.EMPTY, myHandler); } catch (VcsException e) { processRevertError(e); From b7569fae96e57d7bc0e7a3cc7414e334d8e3ab35 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Mon, 10 Feb 2014 18:01:39 +0400 Subject: [PATCH 25/27] IDEA-116775 Use idea home directory as working directory for "revert" operation (not to block current directory in case of reverting rename/move operations) --- .../src/org/jetbrains/idea/svn/revert/CmdRevertClient.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/revert/CmdRevertClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/revert/CmdRevertClient.java index 87f0e23a3fc5..02992c9c591f 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/revert/CmdRevertClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/revert/CmdRevertClient.java @@ -39,7 +39,8 @@ public class CmdRevertClient extends BaseSvnClient implements RevertClient { // TODO: handler should be called in parallel with command execution, but this will be in other thread // TODO: check if that is ok for current handler implementation // TODO: add possibility to invoke "handler.checkCancelled" - process should be killed - CommandExecutor command = CommandUtil.execute(myVcs, SvnTarget.fromFile(paths[0]), SvnCommandName.revert, parameters, null); + CommandExecutor command = + CommandUtil.execute(myVcs, SvnTarget.fromFile(paths[0]), CommandUtil.getHomeDirectory(), SvnCommandName.revert, parameters, null); FileStatusResultParser parser = new FileStatusResultParser(CHANGED_PATH, handler, new RevertStatusConvertor()); parser.parse(command.getOutput()); } From 840b6bee800ebb6c4c312338d927d1ba684de18a Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Mon, 10 Feb 2014 19:51:44 +0400 Subject: [PATCH 26/27] svn: Implemented command line support to logic that preserves changed svn properties during complex reverts - when package rename is reverted, but child files should not be reverted (child files are not not checked in dialog) --- .../svn/properties/CmdPropertyClient.java | 43 +++++++++++++--- .../idea/svn/properties/PropertyClient.java | 3 ++ .../svn/properties/SvnKitPropertyClient.java | 25 +++++++--- .../svn/rollback/SvnRollbackEnvironment.java | 50 ++++++++----------- 4 files changed, 76 insertions(+), 45 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/CmdPropertyClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/CmdPropertyClient.java index 29ff70e59a5f..ce6d2b219bca 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/CmdPropertyClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/CmdPropertyClient.java @@ -8,14 +8,8 @@ import org.jetbrains.idea.svn.api.BaseSvnClient; import org.jetbrains.idea.svn.commandLine.CommandExecutor; import org.jetbrains.idea.svn.commandLine.CommandUtil; import org.jetbrains.idea.svn.commandLine.SvnCommandName; -import org.tmatesoft.svn.core.SVNDepth; -import org.tmatesoft.svn.core.SVNException; -import org.tmatesoft.svn.core.SVNPropertyValue; -import org.tmatesoft.svn.core.SVNURL; -import org.tmatesoft.svn.core.wc.ISVNPropertyHandler; -import org.tmatesoft.svn.core.wc.SVNInfo; -import org.tmatesoft.svn.core.wc.SVNPropertyData; -import org.tmatesoft.svn.core.wc.SVNRevision; +import org.tmatesoft.svn.core.*; +import org.tmatesoft.svn.core.wc.*; import org.tmatesoft.svn.core.wc2.SvnTarget; import javax.xml.bind.JAXBException; @@ -98,6 +92,39 @@ public class CmdPropertyClient extends BaseSvnClient implements PropertyClient { runSetProperty(SvnTarget.fromFile(file), property, null, depth, value, force); } + @Override + public void setProperties(@NotNull File file, @NotNull SVNProperties properties) throws VcsException { + SVNProperties currentProperties = collectPropertiesToDelete(file); + currentProperties.putAll(properties); + + for (String propertyName : currentProperties.nameSet()) { + setProperty(file, propertyName, currentProperties.getSVNPropertyValue(propertyName), SVNDepth.EMPTY, true); + } + } + + @NotNull + private SVNProperties collectPropertiesToDelete(@NotNull File file) throws VcsException { + final SVNProperties result = new SVNProperties(); + + list(SvnTarget.fromFile(file), null, SVNDepth.EMPTY, new ISVNPropertyHandler() { + @Override + public void handleProperty(File path, SVNPropertyData property) throws SVNException { + // null indicates property will be deleted + result.put(property.getName(), (SVNPropertyValue)null); + } + + @Override + public void handleProperty(SVNURL url, SVNPropertyData property) throws SVNException { + } + + @Override + public void handleProperty(long revision, SVNPropertyData property) throws SVNException { + } + }); + + return result; + } + @Override public void setRevisionProperty(@NotNull SvnTarget target, @NotNull String property, diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/PropertyClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/PropertyClient.java index 12bc0e9c885c..b44f7ea12e75 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/PropertyClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/PropertyClient.java @@ -7,6 +7,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.api.SvnClient; import org.tmatesoft.svn.core.SVNDepth; +import org.tmatesoft.svn.core.SVNProperties; import org.tmatesoft.svn.core.SVNPropertyValue; import org.tmatesoft.svn.core.internal.wc.DefaultSVNOptions; import org.tmatesoft.svn.core.wc.ISVNOptions; @@ -51,6 +52,8 @@ public interface PropertyClient extends SvnClient { @Nullable SVNDepth depth, boolean force) throws VcsException; + void setProperties(@NotNull File file, @NotNull SVNProperties properties) throws VcsException; + void setRevisionProperty(@NotNull SvnTarget target, @NotNull String property, @NotNull SVNRevision revision, diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/SvnKitPropertyClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/SvnKitPropertyClient.java index d55eb686371c..c745c4246b67 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/SvnKitPropertyClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/SvnKitPropertyClient.java @@ -5,14 +5,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.api.BaseSvnClient; import org.jetbrains.idea.svn.commandLine.SvnBindException; -import org.tmatesoft.svn.core.SVNDepth; -import org.tmatesoft.svn.core.SVNException; -import org.tmatesoft.svn.core.SVNPropertyValue; -import org.tmatesoft.svn.core.SVNURL; -import org.tmatesoft.svn.core.wc.ISVNPropertyHandler; -import org.tmatesoft.svn.core.wc.SVNPropertyData; -import org.tmatesoft.svn.core.wc.SVNRevision; -import org.tmatesoft.svn.core.wc.SVNWCClient; +import org.tmatesoft.svn.core.*; +import org.tmatesoft.svn.core.wc.*; import org.tmatesoft.svn.core.wc2.SvnTarget; import java.io.File; @@ -83,6 +77,21 @@ public class SvnKitPropertyClient extends BaseSvnClient implements PropertyClien } } + @Override + public void setProperties(@NotNull File file, @NotNull SVNProperties properties) throws VcsException { + try { + createClient().doSetProperty(file, new ISVNPropertyValueProvider() { + @Override + public SVNProperties providePropertyValues(File path, SVNProperties properties) throws SVNException { + return properties; + } + }, true, SVNDepth.EMPTY, null, null); + } + catch (SVNException e) { + throw new SvnBindException(e); + } + } + @Override public void setRevisionProperty(@NotNull SvnTarget target, @NotNull String property, diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/rollback/SvnRollbackEnvironment.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/rollback/SvnRollbackEnvironment.java index 488eed44ab2f..38f15dd271f8 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/rollback/SvnRollbackEnvironment.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/rollback/SvnRollbackEnvironment.java @@ -24,12 +24,13 @@ import com.intellij.openapi.vcs.rollback.RollbackProgressListener; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Processor; -import com.intellij.util.containers.MultiMap; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.*; import org.tmatesoft.svn.core.*; import org.tmatesoft.svn.core.wc.*; +import org.tmatesoft.svn.core.wc2.SvnTarget; import java.io.File; import java.io.IOException; @@ -93,7 +94,7 @@ public class SvnRollbackEnvironment extends DefaultRollbackEnvironment { }; final List fromToModified = new ArrayList(); - final MultiMap properties = new MultiMap(); + final Map properties = ContainerUtil.newHashMap(); moveRenamesToTmp(exceptions, fromToModified, properties, collector); // adds (deletes) // deletes (adds) @@ -116,18 +117,20 @@ public class SvnRollbackEnvironment extends DefaultRollbackEnvironment { private void moveRenamesToTmp(List exceptions, List fromToModified, - final MultiMap properties, + final Map properties, final UnversionedAndNotTouchedFilesGroupCollector collector) { final Map fromTo = collector.getFromTo(); try { final File tmp = FileUtil.createTempDirectory("forRename", ""); - final SVNWCClient client = mySvnVcs.createWCClient(); final ISVNPropertyHandler handler = new ISVNPropertyHandler() { @Override public void handleProperty(File path, SVNPropertyData property) throws SVNException { final ThroughRenameInfo info = collector.findToFile(new FilePathImpl(path, path.isDirectory()), null); if (info != null) { - properties.putValue(info.getTo(), property); + if (!properties.containsKey(info.getTo())) { + properties.put(info.getTo(), new SVNProperties()); + } + properties.get(info.getTo()).put(property.getName(), property.getValue()); } } @@ -147,7 +150,7 @@ public class SvnRollbackEnvironment extends DefaultRollbackEnvironment { final File source = entry.getKey(); final ThroughRenameInfo info = entry.getValue(); if (info.isVersioned()) { - client.doGetProperty(source, null, SVNRevision.UNDEFINED, SVNRevision.WORKING, SVNDepth.EMPTY, handler, null); + mySvnVcs.getFactory(source).createPropertyClient().list(SvnTarget.fromFile(source), SVNRevision.WORKING, SVNDepth.EMPTY, handler); } if (source.isDirectory()) { if (! FileUtil.filesEqual(info.getTo(), info.getFirstTo())) { @@ -165,14 +168,14 @@ public class SvnRollbackEnvironment extends DefaultRollbackEnvironment { catch (IOException e) { exceptions.add(new VcsException(e)); } - catch (SVNException e) { - exceptions.add(new VcsException(e)); + catch(VcsException e) { + exceptions.add(e); } } private void moveGroup(final List exceptions, List fromTo, - MultiMap properties) { + Map properties) { Collections.sort(fromTo, new Comparator() { @Override public int compare(CopiedAsideInfo o1, CopiedAsideInfo o2) { @@ -231,26 +234,15 @@ public class SvnRollbackEnvironment extends DefaultRollbackEnvironment { applyProperties(properties, exceptions); } - private void applyProperties(MultiMap propertiesMap, final List exceptions) { - final SVNWCClient client = mySvnVcs.createWCClient(); - for (Map.Entry> entry : propertiesMap.entrySet()) { - final File file = entry.getKey(); - final Collection propertyDatas = entry.getValue(); - try { - client.doSetProperty(file, new ISVNPropertyValueProvider() { - @Override - public SVNProperties providePropertyValues(File path, SVNProperties properties) throws SVNException { - final SVNProperties result = new SVNProperties(); - for (SVNPropertyData data : propertyDatas) { - result.put(data.getName(), data.getValue()); - } - return result; - } - }, true, SVNDepth.EMPTY, null, null); - } - catch (SVNException e) { - exceptions.add(new VcsException(e)); - } + private void applyProperties(Map propertiesMap, final List exceptions) { + for (Map.Entry entry : propertiesMap.entrySet()) { + File file = entry.getKey(); + try { + mySvnVcs.getFactory(file).createPropertyClient().setProperties(file, entry.getValue()); + } + catch (VcsException e) { + exceptions.add(e); + } } } From 340659b5e5dcca46af03a083150c37cdc822bc63 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Mon, 10 Feb 2014 19:56:38 +0400 Subject: [PATCH 27/27] svn: Refactored SvnUtil.getFileContents - reuse factory selection logic from SvnVcs --- plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java index 7a28423d474e..1e3fd7b1fb18 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java @@ -747,9 +747,7 @@ public class SvnUtil { @Nullable final SVNRevision revision, @Nullable final SVNRevision pegRevision) throws VcsException { - ClientFactory factory = target.isFile() ? vcs.getFactory(target.getFile()) : vcs.getFactory(); - - return factory.createContentClient().getContent(target, revision, pegRevision); + return vcs.getFactory(target).createContentClient().getContent(target, revision, pegRevision); } public static boolean hasDefaultPort(@NotNull SVNURL result) {