String topSrc = ((CopyPair) copyPairs.get(0)).mySource;
for (int i = 1; i < copyPairs.size(); i++) {
CopyPair pair = (CopyPair) copyPairs.get(i);
topSrc = SVNPathUtil.getCommonPathAncestor(topSrc, pair.mySource);
}
SVNWCAccess wcAccess = createWCAccess();
SVNCommitInfo info = null;
ISVNEditor commitEditor = null;
Collection tmpFiles = null;
try {
SVNAdminArea adminArea = wcAccess.probeOpen(new Resource(topSrc), false, SVNWCAccess.INFINITE_DEPTH);
wcAccess.setAnchor(adminArea.getRoot());
String topDstURL = ((CopyPair) copyPairs.get(0)).myDst;
topDstURL = SVNPathUtil.removeTail(topDstURL);
for (int i = 1; i < copyPairs.size(); i++) {
CopyPair pair = (CopyPair) copyPairs.get(i);
topDstURL = SVNPathUtil.getCommonPathAncestor(topDstURL, pair.myDst);
}
// should we use also wcAccess here? i do not think so.
SVNRepository repos = createRepository(SVNURL.parseURIEncoded(topDstURL), adminArea.getRoot(),
wcAccess, true);
List newDirs = new ArrayList();
if (makeParents) {
String rootURL = topDstURL;
SVNNodeKind kind = repos.checkPath("", -1);
while(kind == SVNNodeKind.NONE) {
newDirs.add(rootURL);
rootURL = SVNPathUtil.removeTail(rootURL);
repos.setLocation(SVNURL.parseURIEncoded(rootURL), false);
kind = repos.checkPath("", -1);
}
topDstURL = rootURL;
}
for (int i = 0; i < copyPairs.size(); i++) {
CopyPair pair = (CopyPair) copyPairs.get(i);
SVNEntry entry = wcAccess.getEntry(new Resource(pair.mySource), false);
pair.mySourceRevisionNumber = entry.getRevision();
String dstRelativePath = SVNPathUtil.getPathAsChild(topDstURL, pair.myDst);
dstRelativePath = SVNEncodingUtil.uriDecode(dstRelativePath);
SVNNodeKind kind = repos.checkPath(dstRelativePath, -1);
if (kind != SVNNodeKind.NONE) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.FS_ALREADY_EXISTS,
"Path ''{0}'' already exists", SVNURL.parseURIEncoded(pair.myDst));
SVNErrorManager.error(err, SVNLogType.WC);
}
}
// create commit items list to fetch log messages.
List commitItems = new ArrayList(copyPairs.size());
if (makeParents) {
for (int i = 0; i < newDirs.size(); i++) {
String newDirURL = (String) newDirs.get(i);
SVNURL url = SVNURL.parseURIEncoded(newDirURL);
SVNCommitItem item = new SVNCommitItem(null, url, null, SVNNodeKind.NONE, null, null, true, false, false, false, false, false);
commitItems.add(item);
}
}
for (int i = 0; i < copyPairs.size(); i++) {
CopyPair pair = (CopyPair) copyPairs.get(i);
SVNURL url = SVNURL.parseURIEncoded(pair.myDst);
SVNCommitItem item = new SVNCommitItem(null, url, null, SVNNodeKind.NONE, null, null, true, false, false,
false, false, false);
commitItems.add(item);
}
SVNCommitItem[] commitables = (SVNCommitItem[]) commitItems.toArray(new SVNCommitItem[commitItems.size()]);
message = commitHandler.getCommitMessage(message, commitables);
if (message == null) {
return SVNCommitInfo.NULL;
}
revprops = commitHandler.getRevisionProperties(message, commitables, revprops == null ? new SVNProperties() : revprops);
if (revprops == null) {
return SVNCommitInfo.NULL;
}
Map allCommitables = new TreeMap(SVNCommitUtil.FILE_COMPARATOR);
repos.setLocation(repos.getRepositoryRoot(true), false);
Map pathsToExternalsProps = new SVNHashMap();
for (int i = 0; i < copyPairs.size(); i++) {
CopyPair source = (CopyPair) copyPairs.get(i);
File srcFile = new Resource(source.mySource);
SVNEntry entry = wcAccess.getVersionedEntry(srcFile, false);
SVNAdminArea dirArea;
if (entry.isDirectory()) {
dirArea = wcAccess.retrieve(srcFile);
} else {
dirArea = wcAccess.retrieve(srcFile.getParentFile());
}
pathsToExternalsProps.clear();
Map sourceCommittables = new HashMap();
SVNCommitUtil.harvestCommitables(sourceCommittables, dirArea, srcFile,
null, entry, source.myDst, entry.getURL(), true, false, false, null, SVNDepth.INFINITY,
false, null, commitParameters, pathsToExternalsProps);
// filter out file externals.
// path of the source relative to wcAccess anchor.
String basePath = SVNPathUtil.canonicalizePath(wcAccess.getAnchor().getAbsolutePath());
String sourcePath = SVNPathUtil.canonicalizePath(srcFile.getAbsolutePath());
String path = SVNPathUtil.getRelativePath(basePath, sourcePath);
SVNCommitUtil.filterOutFileExternals(Collections.singletonList(path), sourceCommittables, wcAccess);
allCommitables.putAll(sourceCommittables);
SVNCommitItem item = (SVNCommitItem) allCommitables.get(srcFile);
SVNURL srcURL = entry.getSVNURL();
Map mergeInfo = calculateTargetMergeInfo(srcFile, wcAccess, srcURL,
source.mySourceRevisionNumber, repos, false);
Map wcMergeInfo = SVNPropertiesManager.parseMergeInfo(srcFile, entry, false);
if (wcMergeInfo != null && mergeInfo != null) {
mergeInfo = SVNMergeInfoUtil.mergeMergeInfos(mergeInfo, wcMergeInfo);
} else if (mergeInfo == null) {
mergeInfo = wcMergeInfo;
}
if (mergeInfo != null) {
String mergeInfoString = SVNMergeInfoUtil.formatMergeInfoToString(mergeInfo, null);
setCommitItemProperty(item, SVNProperty.MERGE_INFO, SVNPropertyValue.create(mergeInfoString));
}
if (!pathsToExternalsProps.isEmpty()) {
LinkedList newExternals = new LinkedList();
for (Iterator pathsIter = pathsToExternalsProps.keySet().iterator(); pathsIter.hasNext();) {
File localPath = (File) pathsIter.next();
String externalsPropString = (String) pathsToExternalsProps.get(localPath);
SVNExternal[] externals = SVNExternal.parseExternals(localPath.getAbsolutePath(),
externalsPropString);
boolean introduceVirtualExternalChange = false;
newExternals.clear();
for (int k = 0; k < externals.length; k++) {
File externalWC = new Resource(localPath, externals[k].getPath());
SVNEntry externalEntry = null;
SVNRevision externalsWCRevision = SVNRevision.UNDEFINED;
try {
wcAccess.open(externalWC, false, 0);
externalEntry = wcAccess.getEntry(externalWC, false);
} catch (SVNException svne) {
if (svne instanceof SVNCancelException) {
throw svne;
}
} finally {
wcAccess.closeAdminArea(externalWC);
}
if (externalEntry == null) {
externalEntry = wcAccess.getEntry(externalWC, false);
}
if (externalEntry != null && (externalEntry.isThisDir() || externalEntry.getExternalFilePath() != null)) {
externalsWCRevision = SVNRevision.create(externalEntry.getRevision());
}
SVNEntry ownerEntry = wcAccess.getEntry(localPath, false);
SVNURL ownerURL = null;
if (ownerEntry != null) {
ownerURL = ownerEntry.getSVNURL();
}
if (ownerURL == null) {
// there is no entry for the directory that has external
// property or no url in it?
continue;
}
SVNRevision[] revs = externalsHandler.handleExternal(
externalWC,
externals[k].resolveURL(repos.getRepositoryRoot(true), ownerURL),
externals[k].getRevision(),
externals[k].getPegRevision(),
externals[k].getRawValue(),
externalsWCRevision);
if (revs != null && revs[0].equals(externals[k].getRevision())) {
newExternals.add(externals[k].getRawValue());
} else if (revs != null) {
SVNExternal newExternal = new SVNExternal(externals[k].getPath(),
externals[k].getUnresolvedUrl(), revs[1],
revs[0], true, externals[k].isPegRevisionExplicit(),
externals[k].isNewFormat());
newExternals.add(newExternal.toString());
if (!introduceVirtualExternalChange) {
introduceVirtualExternalChange = true;
}
}
}
if (introduceVirtualExternalChange) {
String newExternalsProp = "";
for (Iterator externalsIter = newExternals.iterator(); externalsIter.hasNext();) {
String external = (String) externalsIter.next();
newExternalsProp += external + '\n';
}
SVNCommitItem itemWithExternalsChanges = (SVNCommitItem) allCommitables.get(localPath);
if (itemWithExternalsChanges != null) {
setCommitItemProperty(itemWithExternalsChanges, SVNProperty.EXTERNALS, SVNPropertyValue.create(newExternalsProp));
} else {
SVNAdminArea childArea = wcAccess.retrieve(localPath);
String relativePath = childArea.getRelativePath(dirArea);
String itemURL = SVNPathUtil.append(source.myDst,
SVNEncodingUtil.uriEncode(relativePath));
itemWithExternalsChanges = new SVNCommitItem(localPath,
SVNURL.parseURIEncoded(itemURL), null, SVNNodeKind.DIR, null, null,
false, false, true, false, false, false);
setCommitItemProperty(itemWithExternalsChanges, SVNProperty.EXTERNALS, SVNPropertyValue.create(newExternalsProp));
allCommitables.put(localPath, itemWithExternalsChanges);
}
}
}
}
}
commitItems = new ArrayList(allCommitables.values());
// in case of 'base' commit, remove all 'deletions', mark all other items as non-modified, remove additions and copies from other urls.
if (myIsDisableLocalModificationsCopying) {
ArrayList harmlessItems = new ArrayList();
for(int i = 0 ; i < commitItems.size(); i++) {
SVNCommitItem item = (SVNCommitItem) commitItems.get(i);
if (item.isDeleted()) {
// deletion or replacement, skip it.
continue;
}
if (item.isAdded()) {
if (!item.isCopied()) {
// this is just new file or directory
continue;
}
SVNURL copyFromURL = item.getCopyFromURL();
if (copyFromURL == null) {
// also skip.
continue;
}
SVNEntry entry = wcAccess.getEntry(item.getFile(), false);
if (entry == null) {
continue;
}
SVNURL expectedURL = entry.getSVNURL();
if (!copyFromURL.equals(expectedURL)) {
// copied from some other location.
continue;
}
}
setCommitItemFlags(item, false, false);
harmlessItems.add(item);
}
commitItems = harmlessItems;
}
// add parents to commits hash?
if (makeParents) {
for (int i = 0; i < newDirs.size(); i++) {
String newDirURL = (String) newDirs.get(i);
SVNURL url = SVNURL.parseURIEncoded(newDirURL);
SVNCommitItem item = new SVNCommitItem(null, url, null, SVNNodeKind.NONE, null, null, true, false, false, false, false, false);
commitItems.add(item);
}
}
commitables = (SVNCommitItem[]) commitItems.toArray(new SVNCommitItem[commitItems.size()]);
for (int i = 0; i < commitables.length; i++) {
setCommitItemAccess(commitables[i], wcAccess);
}
allCommitables = new TreeMap();
SVNURL url = SVNCommitUtil.translateCommitables(commitables, allCommitables);
repos = createRepository(url, null, null, true);
SVNCommitMediator mediator = new SVNCommitMediator(allCommitables);
tmpFiles = mediator.getTmpFiles();
message = SVNCommitUtil.validateCommitMessage(message);
SVNURL rootURL = repos.getRepositoryRoot(true);
SVNPropertiesManager.validateRevisionProperties(revprops);
commitEditor = repos.getCommitEditor(message, null, true, revprops, mediator);
info = SVNCommitter.commit(tmpFiles, allCommitables, rootURL.getPath(), commitEditor);
commitEditor = null;
} catch (SVNCancelException cancel) {
throw cancel;
} catch (SVNException e) {
// wrap error message.
SVNErrorMessage err = e.getErrorMessage().wrap("Commit failed (details follow):");
SVNErrorManager.error(err, SVNLogType.WC);
} finally {
if (tmpFiles != null) {
for (Iterator files = tmpFiles.iterator(); files.hasNext();) {
File file = (File) files.next();
SVNFileUtil.deleteFile(file);
}
}
if (commitEditor != null && info == null) {
// should we hide this exception?
try {
commitEditor.abortEdit();
} catch (SVNException e) {
SVNDebugLog.getDefaultLog().logFine(SVNLogType.WC, e);
}
}
if (wcAccess != null) {
wcAccess.close();
}
}
if (info != null && info.getNewRevision() >= 0) {
dispatchEvent(SVNEventFactory.createSVNEvent(null, SVNNodeKind.NONE, null, info.getNewRevision(), SVNEventAction.COMMIT_COMPLETED, null, null, null), ISVNEventHandler.UNKNOWN);
}