Merge branch 'svn_18_3'

This commit is contained in:
Konstantin Kolosovsky
2014-02-10 20:07:16 +04:00
32 changed files with 892 additions and 810 deletions
@@ -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);
}
@@ -152,12 +152,6 @@ public class SvnUtil {
return info != null && info.getURL() != null ? info.getURL().toString() : null;
}
public static Map<String, File> 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<String, File> myLocations;
public LocationsCrawler(SvnVcs vcs) {
myVcs = vcs;
myLocations = new HashMap<String, File>();
}
public Map<String, File> 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);
@@ -569,6 +534,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 {
@@ -739,6 +705,23 @@ public class SvnUtil {
}
}
public static String getRelativeUrl(@NotNull String parentUrl, @NotNull String childUrl) {
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<String> parts = StringUtil.split(subPath.replace('\\', '/'), "/", true);
@@ -764,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) {
@@ -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<Integer, String> errors = new HashMap<Integer, String>();
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<Integer>() {
@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);
@@ -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);
}
}
@@ -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<Fragment> goBack(final int bunchSize, final Ref<Boolean> myYoungestRead) throws SVNException {
public List<Fragment> goBack(final int bunchSize, final Ref<Boolean> myYoungestRead) throws VcsException {
execute(bunchSize);
myYoungestRead.set(myLiveProvider.isEarliestRevisionWasAccessed());
return new ArrayList<Fragment>(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();
@@ -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();
}
@@ -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;
@@ -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);
}
}
@@ -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<List<CommittedChangeList>> refToList = new Ref<List<CommittedChangeList>>();
final Ref<SVNException> exceptionRef = new Ref<SVNException>();
final Ref<VcsException> exceptionRef = new Ref<VcsException>();
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;
}
@@ -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<String, File> myMap;
public LocationDetector(final SvnVcs vcs) {
myMap = new HashMap<String, File>();
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<File, Boolean> detector) {
for (Map.Entry<String, File> 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<File, Boolean> detector) {
final String relPath = longPath.substring(parentUrl.length());
final File localFile = new File(parentPath, relPath);
return VcsContextFactory.SERVICE.getInstance().createFilePathOn(localFile, detector);
}
}
@@ -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<Pair<SVNLogEntry, Integer>, SVNException> {
private TreeStructureNode<SVNLogEntry> myCurrentHierarchy;
@NotNull private final Consumer<TreeStructureNode<SVNLogEntry>> myConsumer;
public MergeSourceHierarchyBuilder(@NotNull Consumer<TreeStructureNode<SVNLogEntry>> consumer) {
myConsumer = consumer;
}
public void consume(Pair<SVNLogEntry, Integer> 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<SVNLogEntry>(logEntry);
} else {
// just pass
myCurrentHierarchy = null;
myConsumer.consume(new TreeStructureNode<SVNLogEntry>(logEntry));
}
} else {
addToLevel(myCurrentHierarchy, logEntry, mergeLevel);
}
}
public void finish() {
if (myCurrentHierarchy != null) {
myConsumer.consume(myCurrentHierarchy);
}
}
private static void addToLevel(final TreeStructureNode<SVNLogEntry> tree, final SVNLogEntry entry, final int left) {
assert tree != null;
if (left == 0) {
tree.add(entry);
} else {
final List<TreeStructureNode<SVNLogEntry>> children = tree.getChildren();
assert ! children.isEmpty();
addToLevel(children.get(children.size() - 1), entry, left - 1);
}
}
}
@@ -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());
}
}
}
@@ -0,0 +1,179 @@
/*
* 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.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.SVNRevision;
import org.tmatesoft.svn.core.wc2.SvnTarget;
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 SvnChangeList[] changeList;
private SVNRevision revisionBefore;
private SVNURL repositoryUrl;
private SVNURL svnRootUrl;
private SvnRepositoryLocation svnRootLocation;
private String repositoryRelativeUrl;
private FilePath filePath;
public SingleCommittedListProvider(@NotNull SvnVcs vcs, @NotNull VirtualFile file, @NotNull VcsRevisionNumber number) {
myVcs = vcs;
myProject = vcs.getProject();
this.file = file;
this.number = number;
}
public Pair<SvnChangeList, FilePath> run() throws VcsException {
Pair<SvnChangeList, FilePath> result = null;
if (setup()) {
calculate();
result = Pair.create(changeList[0], filePath);
}
return result;
}
private boolean setup() {
boolean result = false;
RootUrlInfo 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);
result = true;
}
return result;
}
private void calculate() throws VcsException {
// TODO: Seems that filePath detection could be replaced with "svn info -r <revisionBefore>" - and not call
// TODO: "svn log -r HEAD:<revisionBefore>" and track copies manually (which also is not correct for all cases).
if (!searchForUrl(svnRootUrl) && !(hasAccess(repositoryUrl) && searchForUrl(repositoryUrl))) {
filePath = searchFromHead(svnRootUrl);
}
else {
if (changeList[0].getChanges().size() == 1) {
final ContentRevision afterRevision = changeList[0].getChanges().iterator().next().getAfterRevision();
filePath = afterRevision != null ? afterRevision.getFile() : filePath;
}
else {
final Change targetChange = changeList[0].getByPath(repositoryRelativeUrl);
filePath = targetChange == null ? searchFromHead(svnRootUrl) : filePath;
}
}
}
private boolean hasAccess(@NotNull SVNURL url) {
return SvnAuthenticationNotifier.passiveValidation(myProject, url);
}
// return changed path, if any
private FilePath searchFromHead(@NotNull SVNURL url) throws VcsException {
final SvnCopyPathTracker pathTracker = new SvnCopyPathTracker(repositoryUrl.toDecodedString(), repositoryRelativeUrl);
SvnTarget target = SvnTarget.fromURL(url);
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
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) {
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);
}
}
};
SvnTarget target = SvnTarget.fromURL(url);
try {
myVcs.getFactory(target).createHistoryClient().doLog(target, revisionBefore, revisionBefore, false, true, false, 1, null, handler);
}
catch (SvnBindException e) {
LOG.info(e);
if (!e.containsCategory(SVNErrorCode.FS_CATEGORY)) {
throw e;
}
}
return changeList[0] != null;
}
}
@@ -16,19 +16,20 @@
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;
import com.intellij.openapi.progress.ProgressIndicator;
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;
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,23 +39,19 @@ 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.*;
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;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.File;
import java.io.IOException;
import java.util.*;
@@ -66,17 +63,15 @@ 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;
private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.history.SvnCommittedChangesProvider");
public SvnCommittedChangesProvider(final Project project) {
myProject = project;
myVcs = SvnVcs.getInstance(myProject);
myZipper = new MyZipper();
myZipper = new SvnCommittedListsZipper(myVcs);
myConnection = myProject.getMessageBus().connect();
@@ -110,17 +105,12 @@ 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);
}
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
@@ -128,49 +118,6 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi
return myZipper;
}
private class MyZipper implements VcsCommittedListsZipper {
public Pair<List<RepositoryLocationGroup>, List<RepositoryLocation>> groupLocations(final List<RepositoryLocation> in) {
final List<RepositoryLocationGroup> groups = new ArrayList<RepositoryLocationGroup>();
final List<RepositoryLocation> singles = new ArrayList<RepositoryLocation>();
final MultiMap<SVNURL, RepositoryLocation> map = new MultiMap<SVNURL, RepositoryLocation>();
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<SVNURL> keys = map.keySet();
for (SVNURL key : keys) {
final Collection<RepositoryLocation> 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<RepositoryLocationGroup>, List<RepositoryLocation>>(groups, singles);
}
public CommittedChangeList zip(final RepositoryLocationGroup group, final List<CommittedChangeList> 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,
@@ -178,30 +125,10 @@ 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));
}
// 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<SVNLogEntry>() {
getCommittedChangesImpl(settings, svnLocation, new String[]{""}, maxCount, new Consumer<SVNLogEntry>() {
public void consume(final SVNLogEntry svnLogEntry) {
final SvnChangeList cl = new SvnChangeList(myVcs, svnLocation, svnLogEntry, repositoryRoot);
if (filter.accepts(cl)) {
@@ -218,29 +145,9 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi
public List<SvnChangeList> getCommittedChanges(ChangeBrowserSettings settings, final RepositoryLocation location, final int maxCount) throws VcsException {
final SvnRepositoryLocation svnLocation = (SvnRepositoryLocation) location;
final ArrayList<SvnChangeList> result = new ArrayList<SvnChangeList>();
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 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();
}
}
getCommittedChangesImpl(settings, svnLocation.getURL(), new String[]{""}, maxCount, new Consumer<SVNLogEntry>() {
getCommittedChangesImpl(settings, svnLocation, new String[]{""}, maxCount, new Consumer<SVNLogEntry>() {
public void consume(final SVNLogEntry svnLogEntry) {
result.add(new SvnChangeList(myVcs, svnLocation, svnLogEntry, repositoryRoot));
}
@@ -254,14 +161,40 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi
final PairConsumer<SvnChangeList, TreeStructureNode<SVNLogEntry>> 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));
}
// TODO: Rewrite this without using SVNKit
final String repositoryRoot = getRepositoryRoot(svnLocation);
final MergeSourceHierarchyBuilder builder = new MergeSourceHierarchyBuilder(new Consumer<TreeStructureNode<SVNLogEntry>>() {
public void consume(TreeStructureNode<SVNLogEntry> node) {
finalConsumer.consume(new SvnChangeList(myVcs, svnLocation, node.getMe(), repositoryRoot), node);
}
});
final SvnMergeSourceTracker mergeSourceTracker = new SvnMergeSourceTracker(new ThrowableConsumer<Pair<SVNLogEntry, Integer>, SVNException>() {
public void consume(Pair<SVNLogEntry, Integer> svnLogEntryIntegerPair) throws SVNException {
builder.consume(svnLogEntryIntegerPair);
}
});
getCommittedChangesImpl(settings, svnLocation, new String[]{""}, maxCount, new Consumer<SVNLogEntry>() {
public void consume(final SVNLogEntry svnLogEntry) {
try {
mergeSourceTracker.consume(svnLogEntry);
}
catch (SVNException e) {
throw new RuntimeException(e);
// will not occur actually but anyway never eat them
}
}
}, true, false);
builder.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();
@@ -273,154 +206,124 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi
repository.closeSession();
}
}
final MergeTrackerProxy proxy = new MergeTrackerProxy(new Consumer<TreeStructureNode<SVNLogEntry>>() {
public void consume(TreeStructureNode<SVNLogEntry> node) {
finalConsumer.consume(new SvnChangeList(myVcs, svnLocation, node.getMe(), repositoryRoot), node);
}
});
final SvnMergeSourceTracker mergeSourceTracker = new SvnMergeSourceTracker(new ThrowableConsumer<Pair<SVNLogEntry, Integer>, SVNException>() {
public void consume(Pair<SVNLogEntry, Integer> svnLogEntryIntegerPair) throws SVNException {
proxy.consume(svnLogEntryIntegerPair);
}
});
getCommittedChangesImpl(settings, svnLocation.getURL(), new String[]{""}, maxCount, new Consumer<SVNLogEntry>() {
public void consume(final SVNLogEntry svnLogEntry) {
try {
mergeSourceTracker.consume(svnLogEntry);
}
catch (SVNException e) {
throw new RuntimeException(e);
// will not occur actually but anyway never eat them
}
}
}, true, false);
proxy.finish();
return repositoryRoot;
}
private static class MergeTrackerProxy implements ThrowableConsumer<Pair<SVNLogEntry, Integer>, SVNException> {
private TreeStructureNode<SVNLogEntry> myCurrentHierarchy;
private final Consumer<TreeStructureNode<SVNLogEntry>> myConsumer;
private MergeTrackerProxy(Consumer<TreeStructureNode<SVNLogEntry>> consumer) {
myConsumer = consumer;
}
public void consume(Pair<SVNLogEntry, Integer> 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<SVNLogEntry>(logEntry);
} else {
// just pass
myCurrentHierarchy = null;
myConsumer.consume(new TreeStructureNode<SVNLogEntry>(logEntry));
}
} else {
addToLevel(myCurrentHierarchy, logEntry, mergeLevel);
}
}
public void finish() {
if (myCurrentHierarchy != null) {
myConsumer.consume(myCurrentHierarchy);
}
}
private static void addToLevel(final TreeStructureNode<SVNLogEntry> tree, final SVNLogEntry entry, final int left) {
assert tree != null;
if (left == 0) {
tree.add(entry);
} else {
final List<TreeStructureNode<SVNLogEntry>> children = tree.getChildren();
assert ! children.isEmpty();
addToLevel(children.get(children.size() - 1), entry, left - 1);
}
}
}
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<SVNLogEntry> 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));
}
try {
SVNLogClient logger = myVcs.createLogClient();
setCollectingChangesProgress(location);
try {
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();
if (progress != null) {
progress.setText2(SvnBundle.message("progress.text2.processing.revision", logEntry.getRevision()));
progress.checkCanceled();
}
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<SVNRevision, VcsException>() {
@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<SVNRevision, VcsException>() {
@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<SVNRevision, VcsException> 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<SVNLogEntry> 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));
}
public ChangeListColumn[] getColumns() {
return new ChangeListColumn[] {
new ChangeListColumn.ChangeListNumberColumn(SvnBundle.message("revision.title")),
@@ -435,39 +338,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);
@@ -478,7 +348,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.<AnAction>singletonList(popup), new Runnable() {
public void run() {
@@ -496,73 +366,7 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi
@Override
public Pair<SvnChangeList, FilePath> 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();
if (root == null) return null;
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);
}
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<SvnChangeList, FilePath>(result[0], path);
}
}
if (result[0].getChanges().size() == 1) {
final Collection<Change> changes = result[0].getChanges();
final Change change = changes.iterator().next();
final ContentRevision afterRevision = change.getAfterRevision();
if (afterRevision != null) {
return new Pair<SvnChangeList, FilePath>(result[0], afterRevision.getFile());
} else {
return new Pair<SvnChangeList, FilePath>(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<SvnChangeList, FilePath>(result[0], path);
}
return new Pair<SvnChangeList, FilePath>(result[0], new FilePathImpl(file));
return new SingleCommittedListProvider(myVcs, file, number).run();
}
@Override
@@ -576,121 +380,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;
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 SVNInfo info, SVNURL svnurl) throws VcsException {
final String repositoryRoot = info.getRepositoryRootURL().toString();
try {
final RenameContext renameContext = new RenameContext(info);
// 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;
}
renameContext.accept(logEntry);
if (logEntry.getRevision() == revisionBefore.getNumber()) {
result[0] = new SvnChangeList(myVcs, svnRepositoryLocation, logEntry, repositoryRoot);
}
}
});
return renameContext.getFilePath(myVcs);
}
catch (SVNException e) {
LOG.info(e);
throw new VcsException(e);
}
}
private void tryExactHit(final SvnRepositoryLocation location,
final SvnChangeList[] result,
SVNLogClient logger,
SVNRevision revisionBefore,
final SVNURL repositoryUrl, SVNURL svnurl) throws VcsException {
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());
}
});
}
catch (SVNException e) {
LOG.info(e);
if (SVNErrorCode.FS_CATEGORY == e.getErrorMessage().getErrorCode().getCategory()) {
// pass to step by step looking for revision
return;
}
throw new VcsException(e);
}
}
public int getFormatVersion() {
return VERSION_WITH_REPLACED_PATHS;
}
@@ -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<RepositoryLocationGroup>, List<RepositoryLocation>> groupLocations(final List<RepositoryLocation> in) {
final List<RepositoryLocationGroup> groups = new ArrayList<RepositoryLocationGroup>();
final List<RepositoryLocation> singles = new ArrayList<RepositoryLocation>();
final MultiMap<SVNURL, RepositoryLocation> map = new MultiMap<SVNURL, RepositoryLocation>();
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<SVNURL> keys = map.keySet();
for (SVNURL key : keys) {
final Collection<RepositoryLocation> 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<RepositoryLocationGroup>, List<RepositoryLocation>>(groups, singles);
}
public CommittedChangeList zip(final RepositoryLocationGroup group, final List<CommittedChangeList> lists) {
return new SvnChangeList(lists, new SvnRepositoryLocation(group.toPresentableString()));
}
public long getNumber(final CommittedChangeList list) {
return list.getNumber();
}
}
@@ -0,0 +1,81 @@
/*
* 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 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 String repositoryUrl, @NotNull String relativeUrl) {
myRepositoryRoot = repositoryUrl;
myCurrentPath = relativeUrl;
}
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);
}
}
@@ -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;
@@ -386,7 +385,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);
}
@@ -415,37 +417,30 @@ 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();
final RepositoryLogEntryHandler repositoryLogEntryHandler =
final RepositoryLogEntryHandler repositoryLogEntryHandler =
new RepositoryLogEntryHandler(myVcs, myUrl, SVNRevision.UNDEFINED, relativeUrl,
new ThrowableConsumer<VcsFileRevision, SVNException>() {
@Override
public void consume(VcsFileRevision revision) throws SVNException {
myConsumer.consume(revision);
throw new SVNCancelException(); // load only one 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, 0, null, 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;
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);
}
private boolean existsNow(SVNURL svnurl) {
@@ -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);
}
}
}
@@ -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);
}
}
@@ -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<CommittedChangeList> 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;
}
@@ -19,15 +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;
@@ -37,48 +38,47 @@ 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<CommittedChangeList> 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<CommittedChangeList> result = new ArrayList<CommittedChangeList>();
loadRevisions(fromIncluding, toIncluding, null, maxCount, result, includingYoungest, includeOldest);
ISVNLogEntryHandler handler = createLogHandler(fromIncluding, toIncluding, includingYoungest, includeOldest, result);
SvnTarget target = SvnTarget.fromURL(myLocation.toSvnUrl());
myVcs.getFactory(target).createHistoryClient().doLog(target, fromIncluding, toIncluding, true, true, false, maxCount, null, handler);
return result;
}
private void loadRevisions(final SVNRevision fromIncluding, final SVNRevision toIncluding, final String author, final int maxCount,
final List<CommittedChangeList> 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<CommittedChangeList> 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()));
}
};
}
}
@@ -18,10 +18,15 @@ 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;
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;
@@ -63,10 +68,24 @@ public class SvnRepositoryLocation implements RepositoryLocation {
public static FilePath getLocalPath(final String fullPath, final NotNullFunction<File, Boolean> 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 {
try {
return SvnUtil.createUrl(myURL);
}
catch (SVNException e) {
throw new SvnBindException(e);
}
}
}
@@ -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,31 +55,30 @@ public class SvnRevisionsNavigationMediator implements CommittedChangesNavigatio
myChunks = new LinkedList<List<Fragment>>();
final SVNURL[] repositoryRoot = new SVNURL[1];
final long[] youngRevision = new long[1];
final VcsException[] exception = new VcsException[1];
final Ref<SVNInfo> infoRef = new Ref<SVNInfo>();
Runnable process = new Runnable() {
@Override
public void run() {
SVNRepository repository = null;
try {
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<ChangesBunch> visualIterator = project.isDefault() ? null :
CommittedChangesCache.getInstance(project).getBackBunchedIterator(vcs, vcsRoot, location, CHUNK_SIZE);
final Iterator<ChangesBunch> internalIterator = project.isDefault() ? null : LoadedRevisionsCache.getInstance(project).iterator(location.getURL());
@@ -87,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;
@@ -133,13 +133,7 @@ public class SvnRevisionsNavigationMediator implements CommittedChangesNavigatio
}
final Ref<Boolean> canNotGoBackRef = new Ref<Boolean>();
final List<Fragment> fragments;
try {
fragments = myChunkFactory.goBack(CHUNK_SIZE, canNotGoBackRef);
}
catch (SVNException e) {
throw new VcsException(e);
}
final List<Fragment> fragments = myChunkFactory.goBack(CHUNK_SIZE, canNotGoBackRef);
myCanNotGoBack = canNotGoBackRef.get().booleanValue();
if (! fragments.isEmpty()) {
@@ -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,
@@ -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,
@@ -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,
@@ -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());
}
@@ -24,13 +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.jetbrains.idea.svn.revert.RevertClient;
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;
@@ -94,12 +94,12 @@ public class SvnRollbackEnvironment extends DefaultRollbackEnvironment {
};
final List<CopiedAsideInfo> fromToModified = new ArrayList<CopiedAsideInfo>();
final MultiMap<File, SVNPropertyData> properties = new MultiMap<File, SVNPropertyData>();
final Map<File, SVNProperties> properties = ContainerUtil.newHashMap();
moveRenamesToTmp(exceptions, fromToModified, properties, collector);
// 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<File> edits = checker.getForEdits();
@@ -117,18 +117,20 @@ public class SvnRollbackEnvironment extends DefaultRollbackEnvironment {
private void moveRenamesToTmp(List<VcsException> exceptions,
List<CopiedAsideInfo> fromToModified,
final MultiMap<File, SVNPropertyData> properties,
final Map<File, SVNProperties> properties,
final UnversionedAndNotTouchedFilesGroupCollector collector) {
final Map<File, ThroughRenameInfo> 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());
}
}
@@ -148,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())) {
@@ -166,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<VcsException> exceptions,
List<CopiedAsideInfo> fromTo,
MultiMap<File, SVNPropertyData> properties) {
Map<File, SVNProperties> properties) {
Collections.sort(fromTo, new Comparator<CopiedAsideInfo>() {
@Override
public int compare(CopiedAsideInfo o1, CopiedAsideInfo o2) {
@@ -232,36 +234,25 @@ public class SvnRollbackEnvironment extends DefaultRollbackEnvironment {
applyProperties(properties, exceptions);
}
private void applyProperties(MultiMap<File, SVNPropertyData> propertiesMap, final List<VcsException> exceptions) {
final SVNWCClient client = mySvnVcs.createWCClient();
for (Map.Entry<File, Collection<SVNPropertyData>> entry : propertiesMap.entrySet()) {
final File file = entry.getKey();
final Collection<SVNPropertyData> 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<File, SVNProperties> propertiesMap, final List<VcsException> exceptions) {
for (Map.Entry<File, SVNProperties> entry : propertiesMap.entrySet()) {
File file = entry.getKey();
try {
mySvnVcs.getFactory(file).createPropertyClient().setProperties(file, entry.getValue());
}
catch (VcsException e) {
exceptions.add(e);
}
}
}
private static class Reverter {
private final RevertClient myClient;
@NotNull private final SvnVcs myVcs;
private ISVNEventHandler myHandler;
private final List<VcsException> myExceptions;
private Reverter(RevertClient client, ISVNEventHandler handler, List<VcsException> exceptions) {
myClient = client;
private Reverter(@NotNull SvnVcs vcs, ISVNEventHandler handler, List<VcsException> exceptions) {
myVcs = vcs;
myHandler = handler;
myExceptions = exceptions;
}
@@ -269,7 +260,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);
@@ -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<VcsFileRevision> list = session.getRevisionList();
@@ -576,15 +549,4 @@ public class TreeConflictRefreshablePanel extends AbstractRefreshablePanel {
return myFileHistoryPanel;
}
}
/*private static class HistoryAsBrowseChangesConflictSide implements AbstractConflictSide<Object> {
public HistoryAsBrowseChangesConflictSide(Project project, SVNConflictVersion version) {
//To change body of created methods use File | Settings | File Templates.
}
@Override
public JPanel createPanel() {
return null;
}
}*/
}
@@ -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());
@@ -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<CommittedChangeList> 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();
@@ -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<CommittedChangeList> 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();