svn: Refactoring - removed OneRecursiveShotMergeInfoWorker, corresponding logic moved to OneShotMergeInfoHelper

This commit is contained in:
Konstantin Kolosovsky
2015-01-29 20:44:21 +03:00
parent 530f923945
commit e9968ac59f
3 changed files with 157 additions and 188 deletions
@@ -18,8 +18,10 @@ package org.jetbrains.idea.svn.integrate;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.svn.SvnUtil;
import org.jetbrains.idea.svn.SvnVcs;
import org.jetbrains.idea.svn.dialogs.WCInfo;
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
/**
* @author Konstantin Kolosovsky.
@@ -33,6 +35,7 @@ public class MergeContext {
@NotNull private final String mySourceUrl;
@NotNull private final SvnVcs myVcs;
@NotNull private final String myTitle;
@NotNull private final String myRepositoryRelativeSourcePath;
public MergeContext(@NotNull SvnVcs vcs,
@NotNull String sourceUrl,
@@ -46,6 +49,7 @@ public class MergeContext {
mySourceUrl = sourceUrl;
myWcInfo = wcInfo;
myTitle = "Merge from " + myBranchName;
myRepositoryRelativeSourcePath = SvnUtil.ensureStartSlash(SVNPathUtil.getRelativePath(myWcInfo.getRepositoryRoot(), mySourceUrl));
}
@NotNull
@@ -73,6 +77,11 @@ public class MergeContext {
return mySourceUrl;
}
@NotNull
public String getRepositoryRelativeSourcePath() {
return myRepositoryRelativeSourcePath;
}
@NotNull
public SvnVcs getVcs() {
return myVcs;
@@ -1,184 +0,0 @@
/*
* Copyright 2000-2010 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.mergeinfo;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vcs.AreaMap;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.util.ObjectUtils;
import com.intellij.util.PairProcessor;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.svn.SvnPropertyKeys;
import org.jetbrains.idea.svn.SvnUtil;
import org.jetbrains.idea.svn.api.Depth;
import org.jetbrains.idea.svn.commandLine.SvnBindException;
import org.jetbrains.idea.svn.integrate.MergeContext;
import org.jetbrains.idea.svn.properties.PropertyConsumer;
import org.jetbrains.idea.svn.properties.PropertyData;
import org.tmatesoft.svn.core.*;
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc2.SvnTarget;
import java.io.File;
import java.util.Map;
public class OneRecursiveShotMergeInfoWorker {
@NotNull private final MergeContext myMergeContext;
// subpath [file] (local) to (subpathURL - merged FROM - to ranges list)
@NotNull private final AreaMap<String, Map<String, SVNMergeRangeList>> myMergeInfoMap;
@NotNull private final Object myLock;
@NotNull private final String myRepositoryRelativeSourcePath;
public OneRecursiveShotMergeInfoWorker(@NotNull MergeContext mergeContext) {
myMergeContext = mergeContext;
myLock = new Object();
// TODO: Rewrite without AreaMap usage
myMergeInfoMap = AreaMap.create(new PairProcessor<String, String>() {
public boolean process(String parentUrl, String childUrl) {
if (".".equals(parentUrl)) return true;
return SVNPathUtil.isAncestor(SvnUtil.ensureStartSlash(parentUrl), SvnUtil.ensureStartSlash(childUrl));
}
});
myRepositoryRelativeSourcePath =
SvnUtil.ensureStartSlash(SVNPathUtil.getRelativePath(myMergeContext.getWcInfo().getRepositoryRoot(), myMergeContext.getSourceUrl()));
}
public void prepare() throws VcsException {
Depth depth = Depth.allOrEmpty(myMergeContext.getVcs().getSvnConfiguration().isCheckNestedForQuickMerge());
File file = myMergeContext.getWcInfo().getRootInfo().getIoFile();
myMergeContext.getVcs().getFactory(file).createPropertyClient()
.getProperty(SvnTarget.fromFile(file), SvnPropertyKeys.MERGE_INFO, SVNRevision.WORKING, depth, createPropertyHandler());
}
@NotNull
private PropertyConsumer createPropertyHandler() {
return new PropertyConsumer() {
public void handleProperty(@NotNull File path, @NotNull PropertyData property) throws SVNException {
String workingCopyRelativePath = getWorkingCopyRelativePath(path);
Map<String, SVNMergeRangeList> mergeInfo;
try {
mergeInfo = BranchInfo.parseMergeInfo(ObjectUtils.assertNotNull(property.getValue()));
}
catch (SvnBindException e) {
throw new SVNException(SVNErrorMessage.create(SVNErrorCode.MERGE_INFO_PARSE_ERROR, e), e);
}
synchronized (myLock) {
myMergeInfoMap.put(toKey(workingCopyRelativePath), mergeInfo);
}
}
public void handleProperty(SVNURL url, PropertyData property) throws SVNException {
}
public void handleProperty(long revision, PropertyData property) throws SVNException {
}
};
}
@NotNull
public SvnMergeInfoCache.MergeCheckResult isMerged(@NotNull String repositoryRelativePath, long revisionNumber) {
String sourceRelativePath =
SVNPathUtil.getRelativePath(myRepositoryRelativeSourcePath, SvnUtil.ensureStartSlash(repositoryRelativePath));
SvnMergeInfoCache.MergeCheckResult result;
if (sourceRelativePath == null) {
// TODO: SVNPathUtil.getRelativePath() is @NotNull - probably we need to check also isEmpty() here?
result = SvnMergeInfoCache.MergeCheckResult.NOT_EXISTS;
}
else {
InfoProcessor processor = new InfoProcessor(sourceRelativePath, myRepositoryRelativeSourcePath, revisionNumber);
synchronized (myLock) {
myMergeInfoMap.getSimiliar(toKey(sourceRelativePath), processor);
}
result = SvnMergeInfoCache.MergeCheckResult.getInstance(processor.isMerged());
}
return result;
}
private static class InfoProcessor implements PairProcessor<String, Map<String, SVNMergeRangeList>> {
@NotNull private final String myRepositoryRelativeSourcePath;
private boolean myIsMerged;
@NotNull private final String mySourceRelativePath;
private final long myRevisionNumber;
public InfoProcessor(@NotNull String sourceRelativePath, @NotNull String repositoryRelativeSourcePath, long revisionNumber) {
mySourceRelativePath = sourceRelativePath;
myRevisionNumber = revisionNumber;
myRepositoryRelativeSourcePath = SvnUtil.ensureStartSlash(repositoryRelativeSourcePath);
}
public boolean isMerged() {
return myIsMerged;
}
// TODO: Try to unify with BranchInfo.processMergeinfoProperty()
public boolean process(@NotNull String workingCopyRelativePath, @NotNull Map<String, SVNMergeRangeList> mergedPathsMap) {
boolean processed = false;
final boolean isCurrentPath = workingCopyRelativePath.equals(mySourceRelativePath);
if (mergedPathsMap.isEmpty()) {
myIsMerged = false;
processed = true;
}
else {
String mergedPathAffectingSourcePath = ContainerUtil.find(mergedPathsMap.keySet(), new Condition<String>() {
@Override
public boolean value(String path) {
return SVNPathUtil.isAncestor(myRepositoryRelativeSourcePath, SvnUtil.ensureStartSlash(path));
}
});
if (mergedPathAffectingSourcePath != null) {
SVNMergeRangeList mergeRangeList = mergedPathsMap.get(mergedPathAffectingSourcePath);
processed = true;
myIsMerged = ContainerUtil.or(mergeRangeList.getRanges(), new Condition<SVNMergeRange>() {
@Override
public boolean value(@NotNull SVNMergeRange range) {
return BranchInfo.isInRange(range, myRevisionNumber) && (range.isInheritable() || isCurrentPath);
}
});
}
}
return processed;
}
}
@NotNull
private String getWorkingCopyRelativePath(@NotNull File file) {
return FileUtil.toSystemIndependentName(
ObjectUtils.assertNotNull(FileUtil.getRelativePath(myMergeContext.getWcInfo().getRootInfo().getIoFile(), file)));
}
@NotNull
private static String toKey(@NotNull String path) {
return SystemInfo.isFileSystemCaseSensitive ? path : path.toUpperCase();
}
}
@@ -15,29 +15,61 @@
*/
package org.jetbrains.idea.svn.mergeinfo;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vcs.AreaMap;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.util.ObjectUtils;
import com.intellij.util.PairProcessor;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.SvnPropertyKeys;
import org.jetbrains.idea.svn.SvnUtil;
import org.jetbrains.idea.svn.api.Depth;
import org.jetbrains.idea.svn.commandLine.SvnBindException;
import org.jetbrains.idea.svn.history.SvnChangeList;
import org.jetbrains.idea.svn.integrate.MergeContext;
import org.jetbrains.idea.svn.properties.PropertyConsumer;
import org.jetbrains.idea.svn.properties.PropertyData;
import org.tmatesoft.svn.core.*;
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc2.SvnTarget;
import java.io.File;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
public class OneShotMergeInfoHelper implements MergeChecker {
@NotNull private final OneRecursiveShotMergeInfoWorker myWorker;
@NotNull private final MergeContext myMergeContext;
@NotNull private final Map<Long, Collection<String>> myPartiallyMerged;
// subpath [file] (local) to (subpathURL - merged FROM - to ranges list)
@NotNull private final AreaMap<String, Map<String, SVNMergeRangeList>> myMergeInfoMap;
@NotNull private final Object myMergeInfoLock;
public OneShotMergeInfoHelper(@NotNull MergeContext mergeContext) {
myWorker = new OneRecursiveShotMergeInfoWorker(mergeContext);
myMergeContext = mergeContext;
myPartiallyMerged = ContainerUtil.newHashMap();
myMergeInfoLock = new Object();
// TODO: Rewrite without AreaMap usage
myMergeInfoMap = AreaMap.create(new PairProcessor<String, String>() {
public boolean process(String parentUrl, String childUrl) {
if (".".equals(parentUrl)) return true;
return SVNPathUtil.isAncestor(SvnUtil.ensureStartSlash(parentUrl), SvnUtil.ensureStartSlash(childUrl));
}
});
}
public void prepare() throws VcsException {
myWorker.prepare();
Depth depth = Depth.allOrEmpty(myMergeContext.getVcs().getSvnConfiguration().isCheckNestedForQuickMerge());
File file = myMergeContext.getWcInfo().getRootInfo().getIoFile();
myMergeContext.getVcs().getFactory(file).createPropertyClient()
.getProperty(SvnTarget.fromFile(file), SvnPropertyKeys.MERGE_INFO, SVNRevision.WORKING, depth, createPropertyHandler());
}
@Nullable
@@ -52,7 +84,7 @@ public class OneShotMergeInfoHelper implements MergeChecker {
for (String path : changeList.getAffectedPaths()) {
//noinspection EnumSwitchStatementWhichMissesCases
switch (myWorker.isMerged(path, changeList.getNumber())) {
switch (checkPath(path, changeList.getNumber())) {
case MERGED:
hasMergedPaths = true;
break;
@@ -70,4 +102,116 @@ public class OneShotMergeInfoHelper implements MergeChecker {
? hasMergedPaths ? SvnMergeInfoCache.MergeCheckResult.MERGED : SvnMergeInfoCache.MergeCheckResult.NOT_EXISTS
: SvnMergeInfoCache.MergeCheckResult.NOT_MERGED;
}
@NotNull
public SvnMergeInfoCache.MergeCheckResult checkPath(@NotNull String repositoryRelativePath, long revisionNumber) {
String sourceRelativePath =
SVNPathUtil.getRelativePath(myMergeContext.getRepositoryRelativeSourcePath(), SvnUtil.ensureStartSlash(repositoryRelativePath));
SvnMergeInfoCache.MergeCheckResult result;
if (sourceRelativePath == null) {
// TODO: SVNPathUtil.getRelativePath() is @NotNull - probably we need to check also isEmpty() here?
result = SvnMergeInfoCache.MergeCheckResult.NOT_EXISTS;
}
else {
InfoProcessor processor = new InfoProcessor(sourceRelativePath, myMergeContext.getRepositoryRelativeSourcePath(), revisionNumber);
synchronized (myMergeInfoLock) {
myMergeInfoMap.getSimiliar(toKey(sourceRelativePath), processor);
}
result = SvnMergeInfoCache.MergeCheckResult.getInstance(processor.isMerged());
}
return result;
}
private static class InfoProcessor implements PairProcessor<String, Map<String, SVNMergeRangeList>> {
@NotNull private final String myRepositoryRelativeSourcePath;
private boolean myIsMerged;
@NotNull private final String mySourceRelativePath;
private final long myRevisionNumber;
public InfoProcessor(@NotNull String sourceRelativePath, @NotNull String repositoryRelativeSourcePath, long revisionNumber) {
mySourceRelativePath = sourceRelativePath;
myRevisionNumber = revisionNumber;
myRepositoryRelativeSourcePath = SvnUtil.ensureStartSlash(repositoryRelativeSourcePath);
}
public boolean isMerged() {
return myIsMerged;
}
// TODO: Try to unify with BranchInfo.processMergeinfoProperty()
public boolean process(@NotNull String workingCopyRelativePath, @NotNull Map<String, SVNMergeRangeList> mergedPathsMap) {
boolean processed = false;
final boolean isCurrentPath = workingCopyRelativePath.equals(mySourceRelativePath);
if (mergedPathsMap.isEmpty()) {
myIsMerged = false;
processed = true;
}
else {
String mergedPathAffectingSourcePath = ContainerUtil.find(mergedPathsMap.keySet(), new Condition<String>() {
@Override
public boolean value(String path) {
return SVNPathUtil.isAncestor(myRepositoryRelativeSourcePath, SvnUtil.ensureStartSlash(path));
}
});
if (mergedPathAffectingSourcePath != null) {
SVNMergeRangeList mergeRangeList = mergedPathsMap.get(mergedPathAffectingSourcePath);
processed = true;
myIsMerged = ContainerUtil.or(mergeRangeList.getRanges(), new Condition<SVNMergeRange>() {
@Override
public boolean value(@NotNull SVNMergeRange range) {
return BranchInfo.isInRange(range, myRevisionNumber) && (range.isInheritable() || isCurrentPath);
}
});
}
}
return processed;
}
}
@NotNull
private PropertyConsumer createPropertyHandler() {
return new PropertyConsumer() {
public void handleProperty(@NotNull File path, @NotNull PropertyData property) throws SVNException {
String workingCopyRelativePath = getWorkingCopyRelativePath(path);
Map<String, SVNMergeRangeList> mergeInfo;
try {
mergeInfo = BranchInfo.parseMergeInfo(ObjectUtils.assertNotNull(property.getValue()));
}
catch (SvnBindException e) {
throw new SVNException(SVNErrorMessage.create(SVNErrorCode.MERGE_INFO_PARSE_ERROR, e), e);
}
synchronized (myMergeInfoLock) {
myMergeInfoMap.put(toKey(workingCopyRelativePath), mergeInfo);
}
}
public void handleProperty(SVNURL url, PropertyData property) throws SVNException {
}
public void handleProperty(long revision, PropertyData property) throws SVNException {
}
};
}
@NotNull
private String getWorkingCopyRelativePath(@NotNull File file) {
return FileUtil.toSystemIndependentName(
ObjectUtils.assertNotNull(FileUtil.getRelativePath(myMergeContext.getWcInfo().getRootInfo().getIoFile(), file)));
}
@NotNull
private static String toKey(@NotNull String path) {
return SystemInfo.isFileSystemCaseSensitive ? path : path.toUpperCase();
}
}