File targetWCPath, boolean dryRun) throws SVNException {
myWCAccess = createWCAccess();
targetWCPath = targetWCPath.getAbsoluteFile();
try {
SVNAdminArea adminArea = myWCAccess.probeOpen(targetWCPath, !dryRun, SVNWCAccess.INFINITE_DEPTH);
SVNEntry targetEntry = myWCAccess.getVersionedEntry(targetWCPath, false);
SVNURL url2 = srcURL == null ? getURL(srcPath) : srcURL;
if (url2 == null) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.ENTRY_MISSING_URL,
"''{0}'' has no URL", srcPath);
SVNErrorManager.error(err, SVNLogType.WC);
}
SVNURL wcReposRoot = getReposRoot(targetWCPath, null, SVNRevision.WORKING, adminArea, myWCAccess);
SVNRepository repository = null;
SVNURL sourceReposRoot = null;
try {
repository = createRepository(wcReposRoot, null, null, true);
sourceReposRoot = repository.getRepositoryRoot(true);
if (!wcReposRoot.equals(sourceReposRoot)) {
Object source = srcPath;
if (source == null) {
source = srcURL;
}
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.CLIENT_UNRELATED_RESOURCES,
"''{0}'' must be from the same repository as ''{1}''", new Object[] { source,
targetWCPath });
SVNErrorManager.error(err, SVNLogType.WC);
}
ensureWCReflectsRepositorySubTree(targetWCPath);
long[] rev1 = { targetEntry.getRevision() };
String sourceReposRelPath = getPathRelativeToRoot(null, url2, null, null, repository);
String targetReposRelPath = getPathRelativeToRoot(targetWCPath, null, wcReposRoot, null,
repository);
SubTreeMergeInfoHandler handler = new SubTreeMergeInfoHandler(targetWCPath, wcReposRoot);
myWCAccess.walkEntries(targetWCPath, handler, true, SVNDepth.INFINITY);
long rev2 = getRevisionNumber(pegRevision, repository, srcPath);
SVNURL[] url1 = { null };
Map unmergedToSourceMergeInfoCatalog = calculateLeftHandSide(url1, rev1, targetReposRelPath,
handler.getSubTreesWithMergeInfoPaths(), rev1[0], sourceReposRelPath, sourceReposRoot, rev2, repository);
SVNLocationEntry youngestCommonAncestor = getYoungestCommonAncestor(null, url2, rev2, null, url1[0],
rev1[0]);
String youngestAncestorPath = youngestCommonAncestor.getPath();
long youngestAncestorRevision = youngestCommonAncestor.getRevision();
if (!(youngestAncestorPath != null && SVNRevision.isValidRevisionNumber(youngestAncestorRevision))) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.CLIENT_NOT_READY_TO_MERGE,
"''{0}@{1}'' must be ancestrally related to ''{2}@{3}''",
new Object[] { url1[0], new Long(rev1[0]), url2, new Long(rev2)});
SVNErrorManager.error(err, SVNLogType.WC);
}
if (rev1[0] > youngestAncestorRevision) {
try {
ensureAllMissingRangesArePhantoms(repository, unmergedToSourceMergeInfoCatalog);
} catch (SVNException svne) {
if (svne.getErrorMessage().getErrorCode() == SVNErrorCode.CLIENT_NOT_READY_TO_MERGE) {
String srcMergeInfoCatalogString = SVNMergeInfoUtil.formatMergeInfoCatalogToString(unmergedToSourceMergeInfoCatalog,
" ", " Missing ranges: ");
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.CLIENT_NOT_READY_TO_MERGE,
"Reintegrate can only be used if revisions {0} through {1} were " +
"previously merged from {2} to the reintegrate source, but this is not the case:\n{3}", new Object[] {
String.valueOf(youngestAncestorRevision + 1), String.valueOf(rev2), targetEntry.getURL(),
srcMergeInfoCatalogString });
SVNErrorManager.error(err, SVNLogType.WC);
}
throw svne;
}