/*
* ====================================================================
* Copyright (c) 2004-2010 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.wc17;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.tmatesoft.svn.core.*;
import org.tmatesoft.svn.core.internal.util.SVNDate;
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
import org.tmatesoft.svn.core.internal.util.SVNSkel;
import org.tmatesoft.svn.core.internal.util.SVNURLUtil;
import org.tmatesoft.svn.core.internal.wc.ISVNUpdateEditor;
import org.tmatesoft.svn.core.internal.wc.SVNCancellableEditor;
import org.tmatesoft.svn.core.internal.wc.SVNConflictVersion;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.core.internal.wc.SVNEventFactory;
import org.tmatesoft.svn.core.internal.wc.SVNFileType;
import org.tmatesoft.svn.core.internal.wc.SVNFileUtil;
import org.tmatesoft.svn.core.internal.wc.admin.SVNChecksumInputStream;
import org.tmatesoft.svn.core.internal.wc.admin.SVNChecksumOutputStream;
import org.tmatesoft.svn.core.internal.wc17.SVNWCContext.MergeInfo;
import org.tmatesoft.svn.core.internal.wc17.SVNWCContext.MergePropertiesInfo;
import org.tmatesoft.svn.core.internal.wc17.SVNWCContext.TranslateInfo;
import org.tmatesoft.svn.core.internal.wc17.SVNWCContext.WritableBaseInfo;
import org.tmatesoft.svn.core.internal.wc17.db.*;
import org.tmatesoft.svn.core.internal.wc17.db.ISVNWCDb.SVNWCDbKind;
import org.tmatesoft.svn.core.internal.wc17.db.ISVNWCDb.SVNWCDbStatus;
import org.tmatesoft.svn.core.internal.wc17.db.ISVNWCDb.WCDbAdditionInfo;
import org.tmatesoft.svn.core.internal.wc17.db.ISVNWCDb.WCDbAdditionInfo.AdditionInfoField;
import org.tmatesoft.svn.core.internal.wc17.db.ISVNWCDb.WCDbBaseInfo;
import org.tmatesoft.svn.core.internal.wc17.db.ISVNWCDb.WCDbBaseInfo.BaseInfoField;
import org.tmatesoft.svn.core.internal.wc17.db.ISVNWCDb.WCDbInfo;
import org.tmatesoft.svn.core.internal.wc17.db.ISVNWCDb.WCDbInfo.InfoField;
import org.tmatesoft.svn.core.internal.wc17.db.ISVNWCDb.WCDbRepositoryInfo;
import org.tmatesoft.svn.core.internal.wc17.db.ISVNWCDb.WCDbRepositoryInfo.RepositoryInfoField;
import org.tmatesoft.svn.core.internal.wc2.ng.SvnNgPropertiesManager;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.io.diff.SVNDeltaProcessor;
import org.tmatesoft.svn.core.io.diff.SVNDiffWindow;
import org.tmatesoft.svn.core.wc.*;
import org.tmatesoft.svn.core.wc2.SvnChecksum;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @version 1.3
* @author TMate Software Ltd.
*/
public class SVNUpdateEditor17 implements ISVNUpdateEditor {
private SVNWCContext myWCContext;
private String myTargetBasename;
private File myAnchorAbspath;
private File myTargetAbspath;
private String[] myExtensionPatterns;
private long myTargetRevision;
private SVNDepth myRequestedDepth;
private boolean myIsDepthSticky;
private boolean myIsUseCommitTimes;
private boolean rootOpened;
private boolean myIsTargetDeleted;
private boolean myIsUnversionedObstructionsAllowed;
private File mySwitchRelpath;
private SVNURL myReposRootURL;
private String myReposUuid;
private Set<File> mySkippedTrees = new HashSet<File>();
private SVNDeltaProcessor myDeltaProcessor;
private SVNExternalsStore myExternalsStore;
private DirectoryBaton myCurrentDirectory;
private FileBaton myCurrentFile;
private boolean myAddsAsModification = true;
private Map<File, Map<String, SVNDirEntry>> myDirEntries;
private boolean myIsCleanCheckout;
private File myWCRootAbsPath;
private Map<File, Map<String, SVNProperties>> myInheritableProperties;
private ISVNConflictHandler myConflictHandler;
public static ISVNUpdateEditor createUpdateEditor(SVNWCContext context,
long targetRevision,
File anchorAbspath,
String targetName,
Map<File, Map<String, SVNProperties>> inheritableProperties,
boolean useCommitTimes,
SVNURL switchURL,
SVNDepth depth,
boolean depthIsSticky,
boolean allowUnversionedObstructions,
boolean addsAsModifications,
boolean serverPerformsFiltering,
boolean cleanCheckout,
ISVNDirFetcher dirFetcher,
SVNExternalsStore externalsStore,
String[] preservedExtensions,
ISVNConflictHandler conflictHandler) throws SVNException {
if (depth == SVNDepth.UNKNOWN) {
depthIsSticky = false;
}
WCDbRepositoryInfo repositoryInfo = context.getDb().scanBaseRepository(anchorAbspath, RepositoryInfoField.rootUrl, RepositoryInfoField.uuid);
assert repositoryInfo != null && repositoryInfo.rootUrl != null && repositoryInfo.uuid != null;
if (switchURL != null && !SVNURLUtil.isAncestor(repositoryInfo.rootUrl, switchURL)) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.WC_INVALID_SWITCH, "''{0}'' is not the same repository as ''{1}''", switchURL, repositoryInfo.rootUrl);
SVNErrorManager.error(err, SVNLogType.WC);
}
SVNUpdateEditor17 editor = new SVNUpdateEditor17();
editor.myIsUseCommitTimes = useCommitTimes;
editor.myTargetRevision = targetRevision;
editor.myReposRootURL = repositoryInfo.rootUrl;
editor.myReposUuid = repositoryInfo.uuid;
editor.myWCContext = context;
editor.myTargetBasename = targetName;
editor.myAnchorAbspath = anchorAbspath;
editor.myWCRootAbsPath = context.getDb().getWCRoot(anchorAbspath);
editor.myInheritableProperties = inheritableProperties;
if (switchURL != null) {
editor.mySwitchRelpath = SVNFileUtil.createFilePath(SVNPathUtil.getRelativePath(repositoryInfo.rootUrl.getPath(), switchURL.getPath()));
}
if ("".equals(targetName) || targetName == null) {
editor.myTargetAbspath = anchorAbspath;
} else {
editor.myTargetAbspath = SVNFileUtil.createFilePath(anchorAbspath, targetName);
}
editor.myRequestedDepth = depth;
editor.myIsDepthSticky = depthIsSticky;
editor.myIsUnversionedObstructionsAllowed = allowUnversionedObstructions;
editor.myAddsAsModification = addsAsModifications;
editor.myIsCleanCheckout = cleanCheckout;
editor.myExtensionPatterns = preservedExtensions;
editor.myExternalsStore = externalsStore;
editor.myConflictHandler = conflictHandler;
if (dirFetcher != null) {
editor.initExcludedDirectoryEntries(dirFetcher);
}
ISVNUpdateEditor result = editor;
if (!serverPerformsFiltering && !depthIsSticky) {
result = new SVNAmbientDepthFilterEditor17(result, context, anchorAbspath, targetName, true);
}
return (ISVNUpdateEditor) SVNCancellableEditor.newInstance(result, context.getEventHandler(), null);
}
public static ISVNUpdateEditor createUpdateEditor(SVNWCContext wcContext, File anchorAbspath, String target, Map<File, Map<String, SVNProperties>> inheritableProperties, SVNURL reposRoot, SVNURL switchURL, SVNExternalsStore externalsStore,
boolean allowUnversionedObstructions, boolean depthIsSticky, SVNDepth depth, String[] preservedExts,
ISVNDirFetcher dirFetcher) throws SVNException {
if (depth == SVNDepth.UNKNOWN) {
depthIsSticky = false;
}
WCDbInfo info = wcContext.getDb().readInfo(anchorAbspath, InfoField.status, InfoField.reposId, InfoField.reposRootUrl, InfoField.reposUuid);
/* ### For adds, REPOS_ROOT and REPOS_UUID would be NULL now. */
if (info.status == SVNWCDbStatus.Added) {
WCDbAdditionInfo addition = wcContext.getDb().scanAddition(anchorAbspath, AdditionInfoField.reposRootUrl, AdditionInfoField.reposUuid);
info.reposRootUrl = addition.reposRootUrl;
info.reposUuid = addition.reposUuid;
}
assert (info.reposRootUrl != null && info.reposUuid != null);
if (switchURL != null) {
if (!SVNPathUtil.isAncestor(info.reposRootUrl.toDecodedString(), switchURL.toDecodedString())) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.WC_INVALID_SWITCH, "''{0}''\nis not the same repository as\n''{1}''", new Object[] {
switchURL.toDecodedString(), info.reposRootUrl.toDecodedString()
});
SVNErrorManager.error(err, SVNLogType.WC);
}
}
return new SVNUpdateEditor17(wcContext, anchorAbspath, target, inheritableProperties, info.reposRootUrl, info.reposUuid, switchURL, externalsStore, allowUnversionedObstructions, depthIsSticky, depth, preservedExts,
dirFetcher);
}
private SVNUpdateEditor17() {
myDirEntries = new HashMap<File, Map<String,SVNDirEntry>>();
myDeltaProcessor = new SVNDeltaProcessor();
mySkippedTrees = new HashSet<File>();
}
public SVNUpdateEditor17(SVNWCContext wcContext, File anchorAbspath, String targetBasename, Map<File, Map<String, SVNProperties>> inheritableProperties, SVNURL reposRootUrl, String reposUuid, SVNURL switchURL, SVNExternalsStore externalsStore,
boolean allowUnversionedObstructions, boolean depthIsSticky, SVNDepth depth, String[] preservedExts, ISVNDirFetcher dirFetcher) throws SVNException {
myWCContext = wcContext;
myAnchorAbspath = anchorAbspath;
myTargetBasename = targetBasename;
myIsUnversionedObstructionsAllowed = allowUnversionedObstructions;
myTargetRevision = -1;
myRequestedDepth = depth;
myIsDepthSticky = depthIsSticky;
myDeltaProcessor = new SVNDeltaProcessor();
myExtensionPatterns = preservedExts;
myTargetAbspath = anchorAbspath;
myReposRootURL = reposRootUrl;
myReposUuid = reposUuid;
myExternalsStore = externalsStore;
myIsUseCommitTimes = myWCContext.getOptions().isUseCommitTimes();
if (myTargetBasename != null) {
myTargetAbspath = SVNFileUtil.createFilePath(myTargetAbspath, myTargetBasename);
}
if ("".equals(myTargetBasename)) {
myTargetBasename = null;
}
if (switchURL != null) {
mySwitchRelpath = SVNFileUtil.createFilePath(SVNPathUtil.getRelativePath(reposRootUrl.getPath(), switchURL.getPath()));
} else {
mySwitchRelpath = null;
}
if (dirFetcher != null) {
initExcludedDirectoryEntries(dirFetcher);
}
myConflictHandler = myWCContext.getOptions().getConflictResolver();
myInheritableProperties = inheritableProperties;
}
private void initExcludedDirectoryEntries(ISVNDirFetcher dirFetcher) throws SVNException {
if (!myIsDepthSticky && SVNDepth.EMPTY.compareTo(myRequestedDepth) <= 0 && myRequestedDepth.compareTo(SVNDepth.INFINITY) < 0 && myRequestedDepth != SVNDepth.UNKNOWN) {
myDirEntries = new HashMap<File, Map<String,SVNDirEntry>>();
WCDbBaseInfo info = null;
try {
info = myWCContext.getDb().getBaseInfo(myTargetAbspath, BaseInfoField.status, BaseInfoField.kind, BaseInfoField.reposRelPath, BaseInfoField.depth);
} catch (SVNException e) {
info = null;
if (e.getErrorMessage().getErrorCode() != SVNErrorCode.WC_PATH_NOT_FOUND) {
throw e;
}
}
if (info != null && info.kind == SVNWCDbKind.Dir && info.status == SVNWCDbStatus.Normal) {
if (info.depth.compareTo(myRequestedDepth) > 0) {
File dirReposRelPath = mySwitchRelpath != null ? mySwitchRelpath : info.reposRelPath;
Map<String, SVNDirEntry> dirEntries = dirFetcher.fetchEntries(myReposRootURL, dirReposRelPath);
if (dirEntries != null && !dirEntries.isEmpty()) {
myDirEntries.put(dirReposRelPath, dirEntries);
}
}
if (myRequestedDepth == SVNDepth.IMMEDIATES) {
Set<String> children = myWCContext.getDb().getBaseChildren(myTargetAbspath);
for (String child : children) {
File childAbsPath = SVNFileUtil.createFilePath(myTargetAbspath, child);
info = myWCContext.getDb().getBaseInfo(childAbsPath, BaseInfoField.status, BaseInfoField.kind, BaseInfoField.reposRelPath, BaseInfoField.depth);
if (info.kind == SVNWCDbKind.Dir && info.status == SVNWCDbStatus.Normal &&
info.depth.compareTo(SVNDepth.EMPTY) > 0) {
File dirReposRelPath = mySwitchRelpath != null ?
SVNFileUtil.createFilePath(mySwitchRelpath, child) : info.reposRelPath;
Map<String, SVNDirEntry> dirEntries = dirFetcher.fetchEntries(myReposRootURL, dirReposRelPath);
if (dirEntries != null && !dirEntries.isEmpty()) {
myDirEntries.put(dirReposRelPath, dirEntries);
}
}
}
}
}
}
}
public void targetRevision(long revision) throws SVNException {
myTargetRevision = revision;
}
public long getTargetRevision() {
return myTargetRevision;
}
private void rememberSkippedTree(File localAbspath) throws SVNException {
assert (SVNFileUtil.isAbsolute(localAbspath));
File relativePath = SVNWCUtils.skipAncestor(getWCRootAbsPath(), localAbspath);
mySkippedTrees.add(relativePath);
return;
}
private File getWCRootAbsPath() throws SVNException {
if (myWCRootAbsPath == null) {
myWCRootAbsPath = myWCContext.getDb().getWCRoot(myAnchorAbspath);
}
return myWCRootAbsPath;
}
public void openRoot(long revision) throws SVNException {
boolean alreadyConflicted;
boolean conflictIgnored;
SVNWCDbStatus baseStatus = SVNWCDbStatus.Normal;
rootOpened = true;
myCurrentDirectory = makeDirectoryBaton(null, null, false);
try {
AlreadyInTreeConflictInfo alreadyInTreeConflictInfo = alreadyInATreeConflict(myCurrentDirectory.localAbsolutePath);
alreadyConflicted = alreadyInTreeConflictInfo.conflicted;
conflictIgnored = alreadyInTreeConflictInfo.ignored;
if (alreadyConflicted) {
rememberSkippedTree(myCurrentDirectory.localAbsolutePath);
rememberSkippedTree(myTargetAbspath);
myCurrentDirectory.skipThis = true;
myCurrentDirectory.alreadyNotified = true;
doNotification(myTargetAbspath, SVNNodeKind.UNKNOWN, SVNEventAction.SKIP_CONFLICTED, null, null);
return;
}
} catch (SVNException e) {
if (e.getErrorMessage().getErrorCode() == SVNErrorCode.WC_PATH_NOT_FOUND) {
throw e;
}
alreadyConflicted = false;
conflictIgnored = false;
}
Structure<StructureFields.NodeInfo> nodeInfoStructure = myWCContext.getDb().readInfo(myCurrentDirectory.localAbsolutePath,
StructureFields.NodeInfo.status, StructureFields.NodeInfo.kind, StructureFields.NodeInfo.revision,
StructureFields.NodeInfo.reposRelPath, StructureFields.NodeInfo.changedRev, StructureFields.NodeInfo.changedDate,
StructureFields.NodeInfo.changedAuthor, StructureFields.NodeInfo.depth, StructureFields.NodeInfo.haveWork);
SVNWCDbStatus status = nodeInfoStructure.get(StructureFields.NodeInfo.status);
SVNWCDbKind kind = nodeInfoStructure.get(StructureFields.NodeInfo.kind);
myCurrentDirectory.oldRevision = nodeInfoStructure.lng(StructureFields.NodeInfo.revision);
myCurrentDirectory.oldReposRelPath = nodeInfoStructure.get(StructureFields.NodeInfo.reposRelPath);
myCurrentDirectory.changedAuthor = nodeInfoStructure.get(StructureFields.NodeInfo.changedAuthor);
myCurrentDirectory.changedRevsion = nodeInfoStructure.lng(StructureFields.NodeInfo.changedRev);
myCurrentDirectory.changedDate = nodeInfoStructure.get(StructureFields.NodeInfo.changedDate);
myCurrentDirectory.ambientDepth = nodeInfoStructure.get(StructureFields.NodeInfo.depth);
boolean haveWork = nodeInfoStructure.is(StructureFields.NodeInfo.haveWork);
if (conflictIgnored) {
myCurrentDirectory.shadowed = true;
} else if (haveWork) {
ISVNWCDb.SVNWCDbBaseMovedToData baseMovedToData = myWCContext.getDb().baseMovedTo(myCurrentDirectory.localAbsolutePath);
File moveSrcRootAbsPath = baseMovedToData.moveSrcRootAbsPath;
if (moveSrcRootAbsPath != null || "".equals(myTargetBasename)) {
WCDbBaseInfo baseInfo = myWCContext.getDb().getBaseInfo(myCurrentDirectory.localAbsolutePath,
BaseInfoField.status, BaseInfoField.revision, BaseInfoField.reposRelPath,
BaseInfoField.changedRev, BaseInfoField.changedDate, BaseInfoField.changedAuthor,
BaseInfoField.depth);
baseStatus = baseInfo.status;
myCurrentDirectory.oldRevision = baseInfo.revision;
myCurrentDirectory.oldReposRelPath = baseInfo.reposRelPath;
myCurrentDirectory.changedRevsion = baseInfo.changedRev;
myCurrentDirectory.changedDate = baseInfo.changedDate;
myCurrentDirectory.changedAuthor = baseInfo.changedAuthor;
myCurrentDirectory.ambientDepth = baseInfo.depth;
}
if (moveSrcRootAbsPath != null) {
SVNSkel treeConflict = SVNSkel.createEmptyList();
SvnWcDbConflicts.addTreeConflict(treeConflict, myWCContext.getDb(), moveSrcRootAbsPath,
SVNConflictReason.MOVED_AWAY, SVNConflictAction.EDIT, moveSrcRootAbsPath);
if (myCurrentDirectory.equals(moveSrcRootAbsPath)) {
completeConflict(treeConflict, moveSrcRootAbsPath,
myCurrentDirectory.oldReposRelPath,
myCurrentDirectory.oldRevision,
myCurrentDirectory.newRelativePath,
SVNNodeKind.DIR, SVNNodeKind.DIR);
myWCContext.getDb().opMarkConflict(moveSrcRootAbsPath, treeConflict, null);
doNotification(moveSrcRootAbsPath, SVNNodeKind.DIR, SVNEventAction.TREE_CONFLICT, null, null);
} else {
myCurrentDirectory.editConflict = treeConflict;
}
}
myCurrentDirectory.shadowed = true;
} else {
baseStatus = status;
}
if ("".equals(myTargetBasename)) {
myCurrentDirectory.wasIncomplete = (baseStatus == SVNWCDbStatus.Incomplete);
myWCContext.getDb().opStartDirectoryUpdateTemp(myCurrentDirectory.localAbsolutePath, myCurrentDirectory.newRelativePath, myTargetRevision);
}
}
private void doNotification(File localAbspath, SVNNodeKind kind, SVNEventAction action, SVNURL url, SVNURL previousURL) throws SVNException {
if (myWCContext.getEventHandler() != null) {
SVNEvent event = new SVNEvent(localAbspath, kind, null, -1, null, null, null, null, action, null, null, null, null, null, null);
event.setURL(url);
event.setPreviousURL(previousURL);
myWCContext.getEventHandler().handleEvent(event, 0);
}
}
private AlreadyInTreeConflictInfo alreadyInATreeConflict(File localAbspath) throws SVNException {
assert (SVNFileUtil.isAbsolute(localAbspath));
File ancestorAbspath = localAbspath;
boolean conflicted = false;
boolean ignored = false;
while (ancestorAbspath != null) {
SVNWCContext.ConflictInfo conflictInfo = myWCContext.getConflicted(ancestorAbspath, false, false, true);
conflicted = conflictInfo.treeConflicted;
ignored = conflictInfo.ignored;
if (conflicted || ignored) {
break;
}
if (myWCContext.getDb().isWCRoot(ancestorAbspath)) {
break;
}
ancestorAbspath = SVNFileUtil.getParentFile(ancestorAbspath);
}
return new AlreadyInTreeConflictInfo(conflicted, ignored);
}
private static class AlreadyInTreeConflictInfo {
public boolean conflicted;
public boolean ignored;
private AlreadyInTreeConflictInfo(boolean conflicted, boolean ignored) {
this.conflicted = conflicted;
this.ignored = ignored;
}
}
public void deleteEntry(String path, long revision) throws SVNException {
if (myCurrentDirectory.skipThis) {
return;
}
myCurrentDirectory.markEdited();
String base = SVNFileUtil.getFileName(SVNFileUtil.createFilePath(path));
File localAbsPath = SVNFileUtil.createFilePath(myCurrentDirectory.localAbsolutePath, base);
boolean isRoot = myWCContext.getDb().isWCRoot(localAbsPath);
if (isRoot) {
rememberSkippedTree(localAbsPath);
doNotification(localAbsPath, SVNNodeKind.UNKNOWN, SVNEventAction.UPDATE_SKIP_OBSTRUCTION, null, null);
return;
}
boolean deletingSwitched;
boolean deletingTarget = localAbsPath.equals(myTargetAbspath);
SVNWCDbStatus baseStatus;
SVNWCDbKind baseKind;
WCDbInfo info = myWCContext.getDb().readInfo(localAbsPath, InfoField.status, InfoField.kind, InfoField.revision, InfoField.reposRelPath, InfoField.conflicted, InfoField.haveBase, InfoField.haveWork);
SVNURL previousURL = info.reposRelPath != null ? SVNWCUtils.join(myReposRootURL, info.reposRelPath) : null;
if (!info.haveWork) {
baseStatus = info.status;
baseKind = info.kind;
} else {
WCDbBaseInfo baseInfo = myWCContext.getDb().getBaseInfo(localAbsPath, BaseInfoField.status, BaseInfoField.kind, BaseInfoField.revision, BaseInfoField.reposRelPath);
baseStatus = baseInfo.status;
baseKind = baseInfo.kind;
info.reposRelPath = baseInfo.reposRelPath;
info.revision = baseInfo.revision;
}
if (myCurrentDirectory.oldReposRelPath != null && info.reposRelPath != null) {
String expectedName = SVNPathUtil.getRelativePath(myCurrentDirectory.oldReposRelPath.getPath(), info.reposRelPath.getPath());
deletingSwitched = (expectedName == null || !expectedName.equals(base));
} else {
deletingSwitched = false;
}
if (myCurrentDirectory.shadowed) {
info.conflicted = false;
} else if (info.conflicted) {
NodeAlreadyConflictedInfo alreadyConflicted = isNodeAlreadyConflicted(localAbsPath);
info.conflicted = alreadyConflicted.conflicted;
}
if (info.conflicted) {
rememberSkippedTree(localAbsPath);
doNotification(localAbsPath, SVNNodeKind.UNKNOWN, SVNEventAction.SKIP_CONFLICTED, null, null);
return;
}
if (baseStatus == SVNWCDbStatus.NotPresent || baseStatus == SVNWCDbStatus.Excluded || baseStatus == SVNWCDbStatus.ServerExcluded) {
myWCContext.getDb().removeBase(localAbsPath, false, false, false, SVNRepository.INVALID_REVISION, null, null);
if (deletingTarget) {
myIsTargetDeleted = true;
}
return;
}
boolean queueDeletes = true;
SVNSkel treeConflict = null;
if (!myCurrentDirectory.shadowed && !myCurrentDirectory.editedObstructed) {
treeConflict = checkTreeConflict(localAbsPath, info.status, true, info.kind == SVNWCDbKind.Dir ? SVNNodeKind.DIR : SVNNodeKind.FILE, SVNConflictAction.DELETE);
} else {
queueDeletes = false;
}
boolean keepAsWorking = false;
if (treeConflict != null) {
if (myCurrentDirectory.deletionConflicts == null) {
myCurrentDirectory.deletionConflicts = new HashMap<String, SVNSkel>();
}
myCurrentDirectory.deletionConflicts.put(base, treeConflict);
Structure<SvnWcDbConflicts.TreeConflictInfo> treeConflictInfoStructure = SvnWcDbConflicts.readTreeConflict(myWCContext.getDb(), localAbsPath, treeConflict);
SVNConflictReason reason = treeConflictInfoStructure.get(SvnWcDbConflicts.TreeConflictInfo.localChange);
if (reason == SVNConflictReason.EDITED ||
reason == SVNConflictReason.OBSTRUCTED) {
keepAsWorking = true;
} else if (reason == SVNConflictReason.DELETED ||
reason == SVNConflictReason.MOVED_AWAY ||
reason == SVNConflictReason.REPLACED) {
//do nothing
} else {
throw new IllegalStateException();
}
}
completeConflict(treeConflict, localAbsPath, info.reposRelPath, info.revision, null, info.kind == SVNWCDbKind.Dir ? SVNNodeKind.DIR : SVNNodeKind.FILE, SVNNodeKind.NONE);
if (!deletingTarget && !deletingSwitched) {
myWCContext.getDb().removeBase(localAbsPath, keepAsWorking, queueDeletes, false, -1, treeConflict, null);
} else {
myWCContext.getDb().removeBase(localAbsPath, keepAsWorking, queueDeletes, false, getTargetRevision(), treeConflict, null);
if (deletingTarget) {
myIsTargetDeleted = true;
} else {
rememberSkippedTree(localAbsPath);
}
}
myWCContext.wqRun(myCurrentDirectory.localAbsolutePath);
if (treeConflict != null) {
doNotification(localAbsPath, SVNNodeKind.UNKNOWN, SVNEventAction.TREE_CONFLICT, null, null);
} else {
SVNEventAction action = SVNEventAction.UPDATE_DELETE;
if (myCurrentDirectory.shadowed || myCurrentDirectory.editedObstructed) {
action = SVNEventAction.UPDATE_SHADOWED_DELETE;
}
doNotification(localAbsPath, info.kind == SVNWCDbKind.Dir ? SVNNodeKind.DIR : SVNNodeKind.FILE, action, null, previousURL);
}
}
private NodeAlreadyConflictedInfo isNodeAlreadyConflicted(File localAbspath) throws SVNException {
NodeAlreadyConflictedInfo alreadyConflictedInfo = new NodeAlreadyConflictedInfo();
List<SVNConflictDescription> conflicts = myWCContext.getDb().readConflicts(localAbspath);
for (SVNConflictDescription cd : conflicts) {
if (cd.isTreeConflict()) {
alreadyConflictedInfo.conflicted = true;
alreadyConflictedInfo.conflictIgnored = false;
return alreadyConflictedInfo;
} else if (cd.isPropertyConflict() || cd.isTextConflict()) {
SVNWCContext.ConflictInfo info = myWCContext.getConflicted(localAbspath, true, true, true);
alreadyConflictedInfo.conflicted = info.textConflicted || info.propConflicted || info.treeConflicted;
alreadyConflictedInfo.conflictIgnored = info.ignored;
return alreadyConflictedInfo;
}
}
alreadyConflictedInfo.conflicted = false;
alreadyConflictedInfo.conflictIgnored = false;
return alreadyConflictedInfo;
}
private static class NodeAlreadyConflictedInfo {
public boolean conflicted;
public boolean conflictIgnored;
}
private SVNSkel checkTreeConflict(File localAbspath, SVNWCDbStatus workingStatus,
boolean existsInRepos, SVNNodeKind expectedKind,
SVNConflictAction action) throws SVNException {
SVNConflictReason reason = null;
boolean modified = false;
boolean allModsAreDeleted = false;
File moveSrcOpRootAbsPath = null;
SVNSkel conflict;
switch (workingStatus) {
case Added:
case MovedHere:
case Copied:
if (!existsInRepos) {
assert action == SVNConflictAction.ADD;
if (workingStatus == SVNWCDbStatus.Added) {
myWCContext.getDb().scanAddition(localAbspath, AdditionInfoField.status);
}
if (workingStatus == SVNWCDbStatus.MovedHere) {
reason = SVNConflictReason.MOVED_HERE;
} else {
reason = SVNConflictReason.ADDED;
}
} else {
ISVNWCDb.SVNWCDbBaseMovedToData baseMovedToData = myWCContext.getDb().baseMovedTo(localAbspath);
moveSrcOpRootAbsPath = baseMovedToData.moveSrcOpRootAbsPath;
if (moveSrcOpRootAbsPath != null) {
reason = SVNConflictReason.MOVED_AWAY;
} else {
reason = SVNConflictReason.REPLACED;
}
}
break;
case Deleted:
ISVNWCDb.SVNWCDbBaseMovedToData baseMovedToData = myWCContext.getDb().baseMovedTo(localAbspath);
moveSrcOpRootAbsPath = baseMovedToData.moveSrcOpRootAbsPath;
if (moveSrcOpRootAbsPath != null) {
reason = SVNConflictReason.MOVED_AWAY;
} else {
reason = SVNConflictReason.DELETED;
}
break;
case Incomplete:
case Normal:
if (action == SVNConflictAction.EDIT) {
if (existsInRepos) {
SVNNodeKind diskKind = SVNFileType.getNodeKind(SVNFileType.getType(localAbspath));
if (diskKind != expectedKind && diskKind != SVNNodeKind.NONE) {
reason = SVNConflictReason.OBSTRUCTED;
break;
}
}
return null;
}
assert action == SVNConflictAction.DELETE;
SVNWCContext.TreeLocalModsInfo treeLocalModsInfo = myWCContext.hasLocalMods(localAbspath, myAnchorAbspath);
modified = treeLocalModsInfo.modificationsFound;
allModsAreDeleted = !treeLocalModsInfo.nonDeleteModificationsFound;
if (modified) {
if (allModsAreDeleted) {
reason = SVNConflictReason.DELETED;
} else {
reason = SVNConflictReason.EDITED;
}
}
break;
case ServerExcluded:
case Excluded:
case NotPresent:
return null;
case BaseDeleted:
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.ASSERTION_FAIL);
SVNErrorManager.error(err, SVNLogType.WC);
break;
default:
break;
}
if (reason == null) {
return null;
}
if (reason == SVNConflictReason.EDITED ||
reason == SVNConflictReason.OBSTRUCTED ||
reason == SVNConflictReason.DELETED ||
reason == SVNConflictReason.MOVED_AWAY ||
reason == SVNConflictReason.REPLACED) {
if (action != SVNConflictAction.EDIT && action != SVNConflictAction.DELETE && action != SVNConflictAction.REPLACE) {
SVNErrorMessage errorMessage = SVNErrorMessage.create(SVNErrorCode.WC_FOUND_CONFLICT, "Unexpected attempt to add a node at path '{{0}}'",
localAbspath);
SVNErrorManager.error(errorMessage, SVNLogType.WC);
}
} else if (reason == SVNConflictReason.ADDED ||
reason == SVNConflictReason.MOVED_HERE) {
if (action != SVNConflictAction.ADD) {
SVNErrorMessage errorMessage = SVNErrorMessage.create(SVNErrorCode.WC_FOUND_CONFLICT, "Unexpected attempt to edit, delete, or replace " +
"a node at path '{{0}}'", localAbspath);
SVNErrorManager.error(errorMessage, SVNLogType.WC);
}
}
conflict = SvnWcDbConflicts.createConflictSkel();
SvnWcDbConflicts.addTreeConflict(conflict, myWCContext.getDb(), localAbspath, reason, action, moveSrcOpRootAbsPath);
return conflict;
}
public void absentDir(String path) throws SVNException {
absentEntry(path, SVNNodeKind.DIR);
}
public void absentFile(String path) throws SVNException {
absentEntry(path, SVNNodeKind.FILE);
}
private void absentEntry(String path, SVNNodeKind nodeKind) throws SVNException {
if (myCurrentDirectory.skipThis) {
return;
}
String name = SVNPathUtil.tail(path);
SVNWCDbKind absentKind = nodeKind == SVNNodeKind.DIR ? SVNWCDbKind.Dir : SVNWCDbKind.File;
myCurrentDirectory.markEdited();
File localAbsPath = SVNFileUtil.createFilePath(myCurrentDirectory.localAbsolutePath, name);
WCDbInfo info = null;
SVNWCDbStatus status = null;
SVNWCDbKind kind = null;
try {
info = myWCContext.getDb().readInfo(localAbsPath, InfoField.status, InfoField.kind);
status = info.status;
kind = info.kind;
} catch (SVNException e) {
if (e.getErrorMessage().getErrorCode() != SVNErrorCode.WC_PATH_NOT_FOUND) {
throw e;
}
status = SVNWCDbStatus.NotPresent;
kind = SVNWCDbKind.Unknown;
}
if (status == SVNWCDbStatus.Normal && kind == SVNWCDbKind.Dir) {
// ok
} else if (status == SVNWCDbStatus.NotPresent || status == SVNWCDbStatus.ServerExcluded || status == SVNWCDbStatus.Excluded) {
// ok
} else {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.WC_OBSTRUCTED_UPDATE, "Failed to mark ''{0}'' absent: item of the same name is already scheduled for addition", path);
SVNErrorManager.error(err, SVNLogType.WC);
}
File reposRelPath = SVNFileUtil.createFilePath(myCurrentDirectory.newRelativePath, name);
myWCContext.getDb().addBaseExcludedNode(localAbsPath, reposRelPath, myReposRootURL, myReposUuid, myTargetRevision, absentKind, SVNWCDbStatus.ServerExcluded, null, null);
}
public void addDir(String path, String copyFromPath, long copyFromRevision) throws SVNException {
assert ((copyFromPath != null && SVNRevision.isValidRevisionNumber(copyFromRevision)) || (copyFromPath == null && !SVNRevision.isValidRevisionNumber(copyFromRevision)));
DirectoryBaton pb = myCurrentDirectory;
myCurrentDirectory = makeDirectoryBaton(path, myCurrentDirectory, true);
DirectoryBaton db = myCurrentDirectory;
if (db.skipThis) {
return;
}
db.markEdited();
boolean conflictIgnored = false;
if (myTargetAbspath.equals(db.localAbsolutePath)) {
db.ambientDepth = (myRequestedDepth == SVNDepth.UNKNOWN) ? SVNDepth.INFINITY : myRequestedDepth;
} else if (myRequestedDepth == SVNDepth.IMMEDIATES || (myRequestedDepth == SVNDepth.UNKNOWN && pb.ambientDepth == SVNDepth.IMMEDIATES)) {
db.ambientDepth = SVNDepth.EMPTY;
} else {
db.ambientDepth = SVNDepth.INFINITY;
}
if (SVNFileUtil.getAdminDirectoryName().equals(db.name)) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.WC_OBSTRUCTED_UPDATE, "Failed to add directory ''{0}'': object of the same name as the administrative directory",
db.localAbsolutePath);
SVNErrorManager.error(err, SVNLogType.WC);
return;
}
SVNNodeKind kind = SVNFileType.getNodeKind(SVNFileType.getType(db.localAbsolutePath));
SVNWCDbStatus status;
SVNWCDbKind wcKind;
boolean conflicted;
boolean versionedLocallyAndPresent;
boolean error = false;
try {
WCDbInfo readInfo = myWCContext.getDb().readInfo(db.localAbsolutePath, InfoField.status, InfoField.kind, InfoField.conflicted, InfoField.reposRelPath);
status = readInfo.status;
wcKind = readInfo.kind;
conflicted = readInfo.conflicted;
versionedLocallyAndPresent = false;
} catch (SVNException e) {
if (e.getErrorMessage().getErrorCode() != SVNErrorCode.WC_PATH_NOT_FOUND) {
throw e;
}
error = true;
wcKind = SVNWCDbKind.Unknown;
status = SVNWCDbStatus.Normal;
conflicted = false;
versionedLocallyAndPresent = false;
}
if (!error) {
if (wcKind == SVNWCDbKind.Dir && status == SVNWCDbStatus.Normal) {
myWCContext.getDb().addBaseNotPresentNode(db.localAbsolutePath, db.newRelativePath, myReposRootURL, myReposUuid, myTargetRevision, SVNWCDbKind.File, null, null);
rememberSkippedTree(db.localAbsolutePath);
db.skipThis = true;
db.alreadyNotified = true;
doNotification(db.localAbsolutePath, SVNNodeKind.DIR, SVNEventAction.UPDATE_SKIP_OBSTRUCTION, db.getURL(), db.getPreviousURL());
return;
} else if (status == SVNWCDbStatus.Normal && (wcKind == SVNWCDbKind.File || wcKind == SVNWCDbKind.Symlink)) {
rememberSkippedTree(db.localAbsolutePath);
db.skipThis = true;
db.alreadyNotified = true;
doNotification(db.localAbsolutePath, SVNNodeKind.FILE, SVNEventAction.UPDATE_SKIP_OBSTRUCTION, db.getURL(), db.getPreviousURL());
return;
} else if (wcKind == SVNWCDbKind.Unknown) {
versionedLocallyAndPresent = false;
} else {
versionedLocallyAndPresent = isNodePresent(status);
}
}
SVNSkel treeConflict = null;
if (conflicted) {
if (pb.deletionConflicts != null) {
treeConflict = pb.deletionConflicts.get(db.name);
}
if (treeConflict != null) {
Structure<SvnWcDbConflicts.TreeConflictInfo> treeConflictInfoStructure = SvnWcDbConflicts.readTreeConflict(myWCContext.getDb(), db.localAbsolutePath, treeConflict);
SVNConflictReason reason = treeConflictInfoStructure.get(SvnWcDbConflicts.TreeConflictInfo.localChange);
treeConflict = SvnWcDbConflicts.createConflictSkel();
SvnWcDbConflicts.addTreeConflict(treeConflict, myWCContext.getDb(), db.localAbsolutePath,
reason, SVNConflictAction.REPLACE, null);
db.editConflict = treeConflict;
treeConflict = null;
db.shadowed = true;
conflicted = false;
} else {
NodeAlreadyConflictedInfo alreadyConflicted = isNodeAlreadyConflicted(db.localAbsolutePath);
conflicted = alreadyConflicted.conflicted;
conflictIgnored = alreadyConflicted.conflictIgnored;
}
}
if (conflicted) {
rememberSkippedTree(db.localAbsolutePath);
db.skipThis = true;
db.alreadyNotified = true;
myWCContext.getDb().addBaseNotPresentNode(db.localAbsolutePath, db.newRelativePath, myReposRootURL, myReposUuid, myTargetRevision, SVNWCDbKind.Dir, null, null);
doNotification(db.localAbsolutePath, SVNNodeKind.DIR, SVNEventAction.SKIP_CONFLICTED, db.getURL(), db.getPreviousURL());
return;
} else if (conflictIgnored) {
db.shadowed = true;
}
if (db.shadowed) {
} else if (versionedLocallyAndPresent) {
SVNWCDbStatus addStatus = SVNWCDbStatus.Normal;
if (status == SVNWCDbStatus.Added) {
addStatus = myWCContext.getDb().scanAddition(db.localAbsolutePath, AdditionInfoField.status).status;
}
boolean localIsNonDir = wcKind != SVNWCDbKind.Dir && status != SVNWCDbStatus.Deleted;
if (!myAddsAsModification || localIsNonDir || addStatus != SVNWCDbStatus.Added) {
treeConflict = checkTreeConflict(db.localAbsolutePath, status, false, wcKind == SVNWCDbKind.Dir ? SVNNodeKind.DIR : SVNNodeKind.FILE, SVNConflictAction.ADD);
}
if (treeConflict == null) {
db.addExisted = true;
} else {
db.shadowed = true;
}
} else if (kind != SVNNodeKind.NONE) {
db.obstructionFound = true;
if (!(kind == SVNNodeKind.DIR && myIsUnversionedObstructionsAllowed)) {
db.shadowed = true;
treeConflict = SvnWcDbConflicts.createConflictSkel();
SvnWcDbConflicts.addTreeConflict(treeConflict, myWCContext.getDb(), db.localAbsolutePath, SVNConflictReason.UNVERSIONED, SVNConflictAction.ADD, null);
db.editConflict = treeConflict;
}
}
if (treeConflict != null) {
completeConflict(treeConflict, db.localAbsolutePath, db.oldReposRelPath, db.oldRevision, db.newRelativePath, wcKind == SVNWCDbKind.Dir ? SVNNodeKind.DIR : SVNNodeKind.FILE, SVNNodeKind.DIR);
}
myWCContext.getDb().opSetNewDirToIncompleteTemp(db.localAbsolutePath, db.newRelativePath, myReposRootURL, myReposUuid, myTargetRevision, db.ambientDepth,
db.shadowed && db.obstructionFound, !db.shadowed && status == SVNWCDbStatus.Added, treeConflict, null);
if (!db.shadowed) {
SVNFileUtil.ensureDirectoryExists(db.localAbsolutePath);
}
if (treeConflict != null) {
db.alreadyNotified = true;
doNotification(db.localAbsolutePath, SVNNodeKind.DIR, SVNEventAction.TREE_CONFLICT, null, null);
}
if (myWCContext.getEventHandler() != null && !db.alreadyNotified && !db.addExisted) {
SVNEventAction action;
if (db.shadowed) {
action = SVNEventAction.UPDATE_SHADOWED_ADD;
} else if (db.obstructionFound || db.addExisted) {
action = SVNEventAction.UPDATE_EXISTS;
} else {
action = SVNEventAction.UPDATE_ADD;
}
db.alreadyNotified = true;
doNotification(db.localAbsolutePath, SVNNodeKind.DIR, action, db.getURL(), db.getPreviousURL());
}
return;
}
public void openDir(String path, long revision) throws SVNException {
DirectoryBaton pb = myCurrentDirectory;
myCurrentDirectory = makeDirectoryBaton(path, pb, false);
DirectoryBaton db = myCurrentDirectory;
if (db.skipThis) {
return;
}
boolean isWCRoot = myWCContext.getDb().isWCRoot(db.localAbsolutePath);
if (isWCRoot) {
rememberSkippedTree(db.localAbsolutePath);
db.skipThis = true;
db.alreadyNotified = true;
doNotification(db.localAbsolutePath, SVNNodeKind.DIR, SVNEventAction.UPDATE_SKIP_OBSTRUCTION, null, null);
return;
}
myWCContext.writeCheck(db.localAbsolutePath);
WCDbInfo readInfo = myWCContext.getDb().readInfo(db.localAbsolutePath, InfoField.reposRelPath, InfoField.status, InfoField.kind, InfoField.revision, InfoField.changedRev, InfoField.changedDate, InfoField.changedAuthor, InfoField.depth, InfoField.haveWork, InfoField.conflicted, InfoField.haveWork);
SVNWCDbStatus status = readInfo.status;
SVNWCDbKind wcKind = readInfo.kind;
db.oldRevision = readInfo.revision;
db.ambientDepth = readInfo.depth;
db.changedRevsion = readInfo.changedRev;
db.changedAuthor = readInfo.changedAuthor;
db.changedDate = readInfo.changedDate;
db.oldReposRelPath = readInfo.reposRelPath;
boolean haveWork = readInfo.haveWork;
boolean conflicted = readInfo.conflicted;
SVNSkel treeConflict = null;
SVNWCDbStatus baseStatus;
if (!haveWork) {
baseStatus = status;
} else {
WCDbBaseInfo baseInfo = myWCContext.getDb().getBaseInfo(db.localAbsolutePath, BaseInfoField.status, BaseInfoField.revision, BaseInfoField.reposRelPath,
BaseInfoField.changedRev, BaseInfoField.changedDate, BaseInfoField.changedAuthor, BaseInfoField.depth);
baseStatus = baseInfo.status;
db.oldRevision = baseInfo.revision;
db.ambientDepth = baseInfo.depth;
db.changedAuthor = baseInfo.changedAuthor;
db.changedDate = baseInfo.changedDate;
db.changedRevsion = baseInfo.changedRev;
db.oldReposRelPath = baseInfo.reposRelPath;
}
db.wasIncomplete = baseStatus == SVNWCDbStatus.Incomplete;
boolean conflictIgnored = false;
if (db.shadowed) {
conflicted = false;
} else if (conflicted) {
NodeAlreadyConflictedInfo alreadyConflicted = isNodeAlreadyConflicted(db.localAbsolutePath);
conflicted = alreadyConflicted.conflicted;
conflictIgnored = alreadyConflicted.conflictIgnored;
}
if (conflicted) {
rememberSkippedTree(db.localAbsolutePath);
db.skipThis = true;
db.alreadyNotified = true;
doNotification(db.localAbsolutePath, SVNNodeKind.UNKNOWN, SVNEventAction.SKIP_CONFLICTED, null, null);
return;
} else if (conflictIgnored) {
db.shadowed = true;
}
if (!db.shadowed) {
treeConflict = checkTreeConflict(db.localAbsolutePath, status, true, wcKind == SVNWCDbKind.Dir ? SVNNodeKind.DIR : SVNNodeKind.FILE, SVNConflictAction.EDIT);
}
if (treeConflict != null) {
db.editConflict = treeConflict;
Structure<SvnWcDbConflicts.TreeConflictInfo> treeConflictInfoStructure = SvnWcDbConflicts.readTreeConflict(myWCContext.getDb(), db.localAbsolutePath, treeConflict);
SVNConflictReason reason = treeConflictInfoStructure.get(SvnWcDbConflicts.TreeConflictInfo.localChange);
assert (reason == SVNConflictReason.DELETED || reason == SVNConflictReason.MOVED_AWAY ||
reason == SVNConflictReason.REPLACED || reason == SVNConflictReason.OBSTRUCTED);
if (reason == SVNConflictReason.OBSTRUCTED) {
db.editedObstructed = true;
} else {
db.shadowed = true;
}
}
myWCContext.getDb().opStartDirectoryUpdateTemp(db.localAbsolutePath, db.newRelativePath, myTargetRevision);
}
public void changeDirProperty(String name, SVNPropertyValue value) throws SVNException {
if (myCurrentDirectory.skipThis) {
return;
}
if (myCurrentDirectory.propChanges == null) {
myCurrentDirectory.propChanges = new SVNProperties();
}
myCurrentDirectory.propChanges.put(name, value);
// TODO use String pool for property names and some of the values.
if (!myCurrentDirectory.edited && SVNProperty.isRegularProperty(name)) {
myCurrentDirectory.markEdited();
}
}
public void closeDir() throws SVNException {
DirectoryBaton db = myCurrentDirectory;
if (db.skipThis) {
maybeBumpDirInfo(db.bumpInfo);
myCurrentDirectory = myCurrentDirectory.parentBaton;
return;
}
SVNSkel conflictSkel = null;
if (db.edited) {
conflictSkel = db.editConflict;
}
SVNSkel allWorkItems = null;
SVNProperties regularProps = new SVNProperties();
SVNProperties entryProps = new SVNProperties();
SVNProperties davProps = new SVNProperties();
SvnNgPropertiesManager.categorizeProperties(db.propChanges, regularProps, entryProps, davProps);
SVNPropertyValue newWCDavURL = davProps != null ? davProps.getSVNPropertyValue(SVNProperty.WC_URL) : null;
if (newWCDavURL == null) {
davProps = null;
}
SVNProperties actualProps = null;
SVNProperties baseProps = null;
if ((!db.addingDir || db.addExisted) && !db.shadowed) {
actualProps = myWCContext.getActualProps(db.localAbsolutePath);
} else {
actualProps = new SVNProperties();
}
if (db.addExisted) {
baseProps = myWCContext.getDb().readPristineProperties(db.localAbsolutePath);
} else if (!db.addingDir) {
baseProps = myWCContext.getDb().getBaseProps(db.localAbsolutePath);
} else {
baseProps = new SVNProperties();
}
SVNStatusType[] propStatus = new SVNStatusType[] {SVNStatusType.UNKNOWN};
SVNProperties newBaseProps = null;
SVNProperties newActualProps = null;
long newChangedRev = -1;
SVNDate newChangedDate = null;
String newChangedAuthor = null;
if (db.wasIncomplete) {
SVNProperties propertiesToDelete = new SVNProperties(baseProps);
if (regularProps == null) {
regularProps = new SVNProperties();
}
for (Iterator<?> names = regularProps.nameSet().iterator(); names.hasNext();) {
String name = (String) names.next();
propertiesToDelete.remove(name);
}
for (Iterator<?> names = propertiesToDelete.nameSet().iterator(); names.hasNext();) {
String name = (String) names.next();
regularProps.put(name, SVNPropertyValue.create(null));
}
}
if (regularProps != null && regularProps.size() > 0) {
if (myExternalsStore != null) {
if (regularProps.containsName(SVNProperty.EXTERNALS)) {
String newValue = regularProps.getStringValue(SVNProperty.EXTERNALS);
String oldValue = baseProps.getStringValue(SVNProperty.EXTERNALS);
if (oldValue == null && newValue == null)
;
else if (oldValue != null && newValue != null && oldValue.equals(newValue))
;
else if (oldValue != null || newValue != null) {
myExternalsStore.addExternal(db.localAbsolutePath, oldValue, newValue);
myExternalsStore.addDepth(db.localAbsolutePath, db.ambientDepth);
}
}
}
if (db.shadowed) {
if (db.addingDir) {
actualProps = new SVNProperties();
} else {
actualProps = baseProps;
}
}
newBaseProps = new SVNProperties(baseProps);
newBaseProps.putAll(regularProps);
MergePropertiesInfo mergeProperiesInfo = null;
mergeProperiesInfo = myWCContext.mergeProperties3(mergeProperiesInfo, db.localAbsolutePath,
null, baseProps, actualProps, regularProps);
newActualProps = mergeProperiesInfo.newActualProperties;
propStatus[0] = mergeProperiesInfo.mergeOutcome;
conflictSkel = mergeProperiesInfo.conflictSkel;
newActualProps.removeNullValues();
newBaseProps.removeNullValues();
// allWorkItems = myWCContext.wqMerge(allWorkItems, mergeProperiesInfo.workItems);
}
AccumulatedChangeInfo change = accumulateLastChange(db.localAbsolutePath, entryProps);
newChangedRev = change.changedRev;
newChangedDate = change.changedDate;
newChangedAuthor = change.changedAuthor;
Map<String, SVNDirEntry> newChildren = myDirEntries != null ? myDirEntries.get(db.newRelativePath) : null;
if (newChildren != null) {
for(String childName : newChildren.keySet()) {
SVNDirEntry childEntry = newChildren.get(childName);
File childAbsPath = SVNFileUtil.createFilePath(db.localAbsolutePath, childName);
if (db.ambientDepth.compareTo(SVNDepth.IMMEDIATES) < 0 && childEntry.getKind() == SVNNodeKind.DIR) {
continue;
}
try {
myWCContext.getDb().getBaseInfo(childAbsPath, BaseInfoField.status);
if (!myWCContext.getDb().isWCRoot(childAbsPath)) {
continue;
}
} catch (SVNException e) {
if (e.getErrorMessage().getErrorCode() != SVNErrorCode.WC_PATH_NOT_FOUND) {
throw e;
}
}
File childRelPath = SVNFileUtil.createFilePath(db.newRelativePath, childName);
SVNWCDbKind childKind = childEntry.getKind() == SVNNodeKind.DIR ? SVNWCDbKind.Dir : SVNWCDbKind.File;
myWCContext.getDb().addBaseNotPresentNode(childAbsPath, childRelPath, myReposRootURL, myReposUuid, myTargetRevision, childKind, null, null);
}
}
if (db.notPresentFiles != null && db.notPresentFiles.size() > 0) {
for(String fileName : db.notPresentFiles) {
File childAbsPath = SVNFileUtil.createFilePath(db.localAbsolutePath, fileName);
File childRelPath = SVNFileUtil.createFilePath(db.newRelativePath, fileName);
myWCContext.getDb().addBaseNotPresentNode(childAbsPath, childRelPath, myReposRootURL, myReposUuid, myTargetRevision, SVNWCDbKind.File, null, null);
}
}
if (db.parentBaton == null && (!"".equals(myTargetBasename) && myTargetBasename != null)) {
// there should be no prop changes here.
} else {
if (newChangedRev >= 0) {
db.changedRevsion = newChangedRev;
}
if (newChangedDate != null && newChangedDate.getTime() != 0) {
db.changedDate = newChangedDate;
}
if (newChangedAuthor != null) {
db.changedAuthor = newChangedAuthor;
}
if (db.ambientDepth == SVNDepth.UNKNOWN) {
db.ambientDepth = SVNDepth.INFINITY;
}
if (myIsDepthSticky && db.ambientDepth != myRequestedDepth) {
if (myRequestedDepth == SVNDepth.INFINITY || (db.localAbsolutePath.equals(myTargetAbspath) && myRequestedDepth.compareTo(db.ambientDepth) > 0)) {
db.ambientDepth = myRequestedDepth;
}
}
SVNProperties props = newBaseProps;
if (props == null) {
props = baseProps;
}
if (davProps != null) {
davProps.removeNullValues();
}
Map<String, SVNProperties> iprops = null;
if (conflictSkel != null) {
completeConflict(conflictSkel, db.localAbsolutePath, db.oldReposRelPath, db.oldRevision,
db.newRelativePath, SVNNodeKind.DIR, SVNNodeKind.DIR);
SVNSkel workItem = myWCContext.conflictCreateMarker(conflictSkel, db.localAbsolutePath);
allWorkItems = myWCContext.wqMerge(allWorkItems, workItem);
}
if (myInheritableProperties != null) {
iprops = myInheritableProperties.remove(db.localAbsolutePath);
}
myWCContext.getDb().addBaseDirectory(db.localAbsolutePath, db.newRelativePath, myReposRootURL, myReposUuid, myTargetRevision, props, db.changedRevsion, db.changedDate, db.changedAuthor, null, db.ambientDepth,
davProps != null && !davProps.isEmpty() ? davProps : null, conflictSkel, !db.shadowed && newBaseProps != null, newActualProps, iprops, allWorkItems);
}
myWCContext.wqRun(db.localAbsolutePath);
if (conflictSkel != null && myConflictHandler != null) {
myWCContext.invokeConflictResolver(db.localAbsolutePath, conflictSkel, myConflictHandler, ISVNCanceller.NULL);
}
if (!db.alreadyNotified && myWCContext.getEventHandler() != null && db.edited) {
SVNEventAction action = null;
if (db.shadowed || db.editedObstructed) {
action = SVNEventAction.UPDATE_SHADOWED_UPDATE;
} else if (db.obstructionFound || db.addExisted) {
action = SVNEventAction.UPDATE_EXISTS;
} else {
action = SVNEventAction.UPDATE_UPDATE;
}
SVNEvent event = new SVNEvent(db.localAbsolutePath, SVNNodeKind.DIR, null, myTargetRevision, null, propStatus[0], null, null, action, null, null, null, null, null, null);
event.setPreviousRevision(db.oldRevision);
event.setURL(db.getURL());
event.setPreviousURL(db.getPreviousURL());
myWCContext.getEventHandler().handleEvent(event, 0);
}
maybeBumpDirInfo(db.bumpInfo);
myCurrentDirectory = myCurrentDirectory.parentBaton;
}
public void addFile(String path, String copyFromPath, long copyFromRevision) throws SVNException {
assert ((copyFromPath != null && SVNRevision.isValidRevisionNumber(copyFromRevision)) || (copyFromPath == null && !SVNRevision.isValidRevisionNumber(copyFromRevision)));
DirectoryBaton pb = myCurrentDirectory;
FileBaton fb = makeFileBaton(pb, path, true);
myCurrentFile = fb;
if (fb.skipThis) {
return;
}
fb.markEdited();
if (SVNFileUtil.getAdminDirectoryName().equals(fb.name)) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.WC_OBSTRUCTED_UPDATE, "Failed to add file ''{0}'' : object of the same name as the administrative directory",
fb.localAbsolutePath);
SVNErrorManager.error(err, SVNLogType.WC);
return;
}
SVNNodeKind kind = SVNNodeKind.NONE;
SVNWCDbKind wcKind = SVNWCDbKind.Unknown;;
SVNWCDbStatus status = SVNWCDbStatus.Normal;
boolean conflicted = false;
boolean versionedLocallyAndPresent = false;
boolean error = false;
boolean conflictIgnored = false;
SVNSkel treeConflict = null;
if (!myIsCleanCheckout) {
kind = SVNFileType.getNodeKind(SVNFileType.getType(fb.localAbsolutePath));
try {
WCDbInfo readInfo = myWCContext.getDb().readInfo(fb.localAbsolutePath, InfoField.status, InfoField.kind, InfoField.conflicted, InfoField.reposRelPath);
status = readInfo.status;
wcKind = readInfo.kind;
conflicted = readInfo.conflicted;
versionedLocallyAndPresent = isNodePresent(status);
} catch (SVNException e) {
if (e.getErrorMessage().getErrorCode() != SVNErrorCode.WC_PATH_NOT_FOUND) {
throw e;
}
error = true;
wcKind = SVNWCDbKind.Unknown;
conflicted = false;
versionedLocallyAndPresent = false;
}
}
if (!error) {
if (wcKind == SVNWCDbKind.Dir && status == SVNWCDbStatus.Normal) {
if (pb.notPresentFiles == null) {
pb.notPresentFiles = new HashSet<String>();
}
pb.notPresentFiles.add(fb.name);
rememberSkippedTree(fb.localAbsolutePath);
fb.skipThis = true;
fb.alreadyNotified = true;
doNotification(fb.localAbsolutePath, SVNNodeKind.FILE, SVNEventAction.UPDATE_SKIP_OBSTRUCTION, fb.getURL(), fb.getPreviousURL());
return;
} else if (status == SVNWCDbStatus.Normal && (wcKind == SVNWCDbKind.File || wcKind == SVNWCDbKind.Symlink)) {
rememberSkippedTree(fb.localAbsolutePath);
fb.skipThis = true;
fb.alreadyNotified = true;
doNotification(fb.localAbsolutePath, SVNNodeKind.FILE, SVNEventAction.UPDATE_SKIP_OBSTRUCTION, fb.getURL(), fb.getPreviousURL());
return;
} else if (wcKind == SVNWCDbKind.Unknown) {
versionedLocallyAndPresent = false;
} else {
versionedLocallyAndPresent = isNodePresent(status);
}
}
if (fb.shadowed) {
conflicted = false;
} else if (conflicted) {
if (pb.deletionConflicts != null) {
treeConflict = pb.deletionConflicts.get(fb.name);
}
if (treeConflict != null) {
Structure<SvnWcDbConflicts.TreeConflictInfo> treeConflictInfoStructure = SvnWcDbConflicts.readTreeConflict(myWCContext.getDb(), fb.localAbsolutePath, treeConflict);
SVNConflictReason reason = treeConflictInfoStructure.get(SvnWcDbConflicts.TreeConflictInfo.localChange);
treeConflict = SvnWcDbConflicts.createConflictSkel();
SvnWcDbConflicts.addTreeConflict(treeConflict, myWCContext.getDb(), fb.localAbsolutePath, reason, SVNConflictAction.REPLACE, null);
fb.editConflict = treeConflict;
treeConflict = null;
fb.shadowed = true;
conflicted = false;
} else {
NodeAlreadyConflictedInfo alreadyConflicted = isNodeAlreadyConflicted(fb.localAbsolutePath);
conflicted = alreadyConflicted.conflicted;
conflictIgnored = alreadyConflicted.conflictIgnored;
}
}
if (conflicted) {
rememberSkippedTree(fb.localAbsolutePath);
fb.skipThis = true;
fb.alreadyNotified = true;
if (pb.notPresentFiles == null) {
pb.notPresentFiles = new HashSet<String>();
}
pb.notPresentFiles.add(fb.name);
doNotification(fb.localAbsolutePath, SVNNodeKind.UNKNOWN, SVNEventAction.SKIP_CONFLICTED, fb.getURL(), fb.getPreviousURL());
return;
} else if (conflictIgnored) {
fb.shadowed = true;
}
if (fb.shadowed) {
//
} else if (versionedLocallyAndPresent) {
boolean localIsFile = false;
if (status == SVNWCDbStatus.Added) {
status = myWCContext.getDb().scanAddition(fb.localAbsolutePath, AdditionInfoField.status).status;
}
localIsFile = wcKind == SVNWCDbKind.File || wcKind == SVNWCDbKind.Symlink;
if (!myAddsAsModification || !localIsFile || status != SVNWCDbStatus.Added) {
treeConflict = checkTreeConflict(fb.localAbsolutePath, status, false, wcKind == SVNWCDbKind.Dir ? SVNNodeKind.DIR : SVNNodeKind.FILE, SVNConflictAction.ADD);
}
if (treeConflict == null) {
fb.addExisted = true;
} else {
fb.shadowed = true;
}
} else if (kind != SVNNodeKind.NONE) {
fb.obstructionFound = true;
if (!(kind == SVNNodeKind.FILE && myIsUnversionedObstructionsAllowed)) {
fb.shadowed = true;
treeConflict = SvnWcDbConflicts.createConflictSkel();
SvnWcDbConflicts.addTreeConflict(treeConflict, myWCContext.getDb(), fb.localAbsolutePath, SVNConflictReason.UNVERSIONED, SVNConflictAction.ADD, null);
}
}
if (pb.parentBaton != null || myTargetBasename == null || "".equals(myTargetBasename) || !fb.localAbsolutePath.equals(myTargetAbspath)) {
if (pb.notPresentFiles == null) {
pb.notPresentFiles = new HashSet<String>();
}
pb.notPresentFiles.add(fb.name);
}
if (treeConflict != null) {
completeConflict(treeConflict, fb.localAbsolutePath, fb.oldReposRelPath, fb.oldRevision, fb.newRelativePath, wcKind == SVNWCDbKind.Dir ? SVNNodeKind.DIR : SVNNodeKind.FILE, SVNNodeKind.FILE);
myWCContext.getDb().opMarkConflict(fb.localAbsolutePath, treeConflict, null);
fb.alreadyNotified = true;
doNotification(fb.localAbsolutePath, SVNNodeKind.FILE, SVNEventAction.TREE_CONFLICT, fb.getURL(), fb.getPreviousURL());
}
return;
}
public void openFile(String path, long revision) throws SVNException {
DirectoryBaton pb = myCurrentDirectory;
FileBaton fb = makeFileBaton(pb, path, false);
myCurrentFile = fb;
if (fb.skipThis) {
return;
}
boolean isRoot = myWCContext.getDb().isWCRoot(fb.localAbsolutePath);
if (isRoot) {
rememberSkippedTree(fb.localAbsolutePath);
fb.skipThis = true;
fb.alreadyNotified = true;
doNotification(fb.localAbsolutePath, SVNNodeKind.FILE, SVNEventAction.UPDATE_SKIP_OBSTRUCTION, null, null);
return;
}
boolean conflicted = false;
boolean conflictIgnored = false;
SVNWCDbStatus status;
SVNWCDbKind kind = SVNWCDbKind.Unknown;
SVNSkel treeConflict = null;
WCDbInfo readInfo = myWCContext.getDb().readInfo(fb.localAbsolutePath, InfoField.status, InfoField.kind,
InfoField.revision, InfoField.changedRev, InfoField.changedDate, InfoField.changedRev,
InfoField.checksum, InfoField.haveWork, InfoField.conflicted, InfoField.propsMod, InfoField.reposRelPath);
status = readInfo.status;
fb.changedAuthor = readInfo.changedAuthor;
fb.changedDate = readInfo.changedDate;
fb.changedRevison = readInfo.changedRev;
fb.oldRevision = readInfo.revision;
fb.originalChecksum = readInfo.checksum;
fb.oldReposRelPath = readInfo.reposRelPath;
fb.localPropMods = readInfo.propsMod;
conflicted = readInfo.conflicted;
if (readInfo.haveWork) {
WCDbBaseInfo baseInfo = myWCContext.getDb().getBaseInfo(fb.localAbsolutePath, BaseInfoField.revision, BaseInfoField.reposRelPath,
BaseInfoField.changedRev, BaseInfoField.changedAuthor, BaseInfoField.changedDate,
BaseInfoField.checksum);
fb.changedAuthor = baseInfo.changedAuthor;
fb.changedDate = baseInfo.changedDate;
fb.changedRevison = baseInfo.changedRev;
fb.oldRevision = baseInfo.revision;
fb.originalChecksum = baseInfo.checksum;
fb.oldReposRelPath = baseInfo.reposRelPath;
}
if (fb.shadowed) {
conflicted = false;
} else if (conflicted) {
NodeAlreadyConflictedInfo alreadyConflicted = isNodeAlreadyConflicted(fb.localAbsolutePath);
conflicted = alreadyConflicted.conflicted;
conflictIgnored = alreadyConflicted.conflictIgnored;
}
if (conflicted ) {
rememberSkippedTree(fb.localAbsolutePath);
fb.skipThis = true;
fb.alreadyNotified = true;
doNotification(fb.localAbsolutePath, SVNNodeKind.UNKNOWN, SVNEventAction.SKIP_CONFLICTED, fb.getURL(), fb.getPreviousURL());
return;
} else if (conflictIgnored) {
fb.shadowed = true;
}
if (!fb.shadowed) {
treeConflict = checkTreeConflict(fb.localAbsolutePath, status, true, kind == SVNWCDbKind.Dir ? SVNNodeKind.DIR : SVNNodeKind.FILE, SVNConflictAction.EDIT);
}
if (treeConflict != null) {
fb.editConflict = treeConflict;
Structure<SvnWcDbConflicts.TreeConflictInfo> treeConflictInfoStructure = SvnWcDbConflicts.readTreeConflict(myWCContext.getDb(), fb.localAbsolutePath, treeConflict);
SVNConflictReason reason = treeConflictInfoStructure.get(SvnWcDbConflicts.TreeConflictInfo.localChange);
assert reason == SVNConflictReason.DELETED || reason == SVNConflictReason.MOVED_AWAY ||
reason == SVNConflictReason.REPLACED || reason == SVNConflictReason.OBSTRUCTED;
if (reason == SVNConflictReason.OBSTRUCTED) {
fb.editObstructed = true;
} else {
fb.shadowed = true;
}
}
}
public void changeFileProperty(String path, String propertyName, SVNPropertyValue propertyValue) throws SVNException {
FileBaton fb = myCurrentFile;
if (fb.skipThis) {
return;
}
myCurrentFile.propChanges.put(propertyName, propertyValue);
if (!fb.edited && SVNProperty.isRegularProperty(propertyName)) {
fb.markEdited();
}
if (!fb.shadowed && (SVNProperty.SPECIAL.equals(propertyName))) {
boolean becomesSymlink = propertyValue != null;
boolean wasSymlink;
boolean modified = false;
if (fb.addingFile) {
wasSymlink = becomesSymlink;
} else {
final SVNProperties props = myWCContext.getDb().getBaseProps(fb.localAbsolutePath);
wasSymlink = props != null && props.getSVNPropertyValue(SVNProperty.SPECIAL) != null;
}
if (wasSymlink != becomesSymlink) {
if (fb.localPropMods) {
modified = true;
} else {
modified = myWCContext.isTextModified(fb.localAbsolutePath, false);
}
if (modified) {
if (fb.editConflict == null) {
fb.editConflict = SvnWcDbConflicts.createConflictSkel();
}
SvnWcDbConflicts.addTreeConflict(fb.editConflict, myWCContext.getDb(), fb.localAbsolutePath, SVNConflictReason.EDITED, SVNConflictAction.REPLACE, null);
completeConflict(fb.editConflict, fb.localAbsolutePath, fb.oldReposRelPath, fb.oldRevision, fb.newRelativePath, SVNNodeKind.FILE, SVNNodeKind.FILE);
((SVNWCDb)myWCContext.getDb()).opMakeCopy(fb.localAbsolutePath, fb.editConflict, null);
doNotification(fb.localAbsolutePath, SVNNodeKind.FILE, SVNEventAction.TREE_CONFLICT, fb.getURL(), fb.getPreviousURL());
fb.shadowed = true;
fb.addExisted = false;
fb.alreadyNotified = true;
}
}
}
return;
}
public void closeFile(String path, String expectedMd5Digest) throws SVNException {
FileBaton fb = myCurrentFile;
if (fb.skipThis) {
maybeBumpDirInfo(fb.bumpInfo);
return;
}
SVNSkel conflictSkel = null;
if (fb.edited) {
conflictSkel = fb.editConflict;
}
SvnChecksum expectedMd5Checksum = null;
if (expectedMd5Digest != null) {
expectedMd5Checksum = new SvnChecksum(SvnChecksum.Kind.md5, expectedMd5Digest);
}
if (expectedMd5Checksum != null && fb.newTextBaseMD5Digest != null &&
!expectedMd5Checksum.getDigest().equals(fb.newTextBaseMD5Digest)) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.CHECKSUM_MISMATCH, "Checksum mismatch for ''{0}''; expected: ''{1}'', actual: ''{2}''", new Object[] {
fb.localAbsolutePath, expectedMd5Checksum, fb.newTextBaseMD5Digest
});
SVNErrorManager.error(err, SVNLogType.WC);
}
SVNProperties regularPropChanges = new SVNProperties();
SVNProperties entryProps = new SVNProperties();
SVNProperties davProps = new SVNProperties();
SvnNgPropertiesManager.categorizeProperties(fb.propChanges, regularPropChanges, entryProps, davProps);
SVNPropertyValue newWCDavURL = davProps != null ? davProps.getSVNPropertyValue(SVNProperty.WC_URL) : null;
if (newWCDavURL == null) {
davProps = null;
}
AccumulatedChangeInfo lastChange = accumulateLastChange(fb.localAbsolutePath, entryProps);
long newChangedRev = lastChange.changedRev;
SVNDate newChangedDate = lastChange.changedDate;
String newChangedAuthor = lastChange.changedAuthor;
if (newChangedRev >= 0) {
fb.changedRevison = newChangedRev;
}
if (newChangedDate != null) {
fb.changedDate = newChangedDate;
}
if (newChangedAuthor != null) {
fb.changedAuthor = newChangedAuthor;
}
SVNStatusType lockState = SVNStatusType.LOCK_UNCHANGED;
for (Iterator<?> i = entryProps.nameSet().iterator(); i.hasNext();) {
String name = (String) i.next();
if (SVNProperty.LOCK_TOKEN.equals(name)) {
if (mySwitchRelpath == null || fb.newRelativePath.equals(fb.oldReposRelPath)) {
assert (entryProps.getStringValue(name) == null);
myWCContext.getDb().removeLock(fb.localAbsolutePath);
lockState = SVNStatusType.LOCK_UNLOCKED;
break;
}
}
}
SVNProperties localActualProps = null;
SVNProperties currentBaseProps = null;
SVNProperties currentActualProps = null;
if ((!fb.addingFile || fb.addExisted) && !fb.shadowed) {
localActualProps = myWCContext.getActualProps(fb.localAbsolutePath);
}
if (localActualProps == null) {
localActualProps = new SVNProperties();
}
if (fb.addExisted) {
currentBaseProps = myWCContext.getDb().readPristineProperties(fb.localAbsolutePath);
currentActualProps = localActualProps;
} else if (!fb.addingFile) {
currentBaseProps = myWCContext.getDb().getBaseProps(fb.localAbsolutePath);
currentActualProps = localActualProps;
}
if (currentBaseProps == null) {
currentBaseProps = new SVNProperties();
}
if (currentActualProps == null) {
currentActualProps = new SVNProperties();
}
SVNStatusType[] propState = new SVNStatusType[] {SVNStatusType.UNKNOWN};
SVNStatusType contentState = null;
SVNProperties newBaseProps = new SVNProperties();
SVNProperties newActualProps = new SVNProperties();
SVNSkel allWorkItems = null;
boolean keepRecordedInfo = false;
if (!fb.shadowed) {
boolean installPristine = false;
MergePropertiesInfo info = new MergePropertiesInfo();
info.newActualProperties = newActualProps;
info.newBaseProperties = new SVNProperties(currentBaseProps);
info.newBaseProperties.putAll(regularPropChanges);
info.conflictSkel = conflictSkel;
info = myWCContext.mergeProperties3(info, fb.localAbsolutePath,
null, currentBaseProps, currentActualProps, regularPropChanges);
newActualProps = info.newActualProperties;
newBaseProps = info.newBaseProperties;
propState[0] = info.mergeOutcome;
conflictSkel = info.conflictSkel;
allWorkItems = myWCContext.wqMerge(allWorkItems, info.workItems);
newActualProps.removeNullValues();
newBaseProps.removeNullValues();
File installFrom = null;
if (!fb.obstructionFound && !fb.editObstructed) {
MergeFileInfo fileInfo = new MergeFileInfo();
fileInfo.conflictSkel = conflictSkel;
fileInfo.workItem = allWorkItems;
try {
fileInfo = mergeFile(fb, fileInfo, currentActualProps, fb.changedDate);
contentState = fileInfo.contentState;
installFrom = fileInfo.installFrom;
installPristine = fileInfo.installPristine;
conflictSkel = fileInfo.conflictSkel;
} catch (SVNException e) {
if (SVNWCContext.isErrorAccess(e)) {
doNotification(fb.localAbsolutePath, SVNNodeKind.FILE, SVNEventAction.UPDATE_SKIP_ACCESS_DENINED, fb.getURL(), fb.getPreviousURL());
rememberSkippedTree(fb.localAbsolutePath);
fb.skipThis = true;
maybeBumpDirInfo(fb.bumpInfo);
return;
}
throw e;
}
if (fileInfo != null) {
allWorkItems = myWCContext.wqMerge(allWorkItems, fileInfo.workItem);
}
} else {
installPristine = false;
if (fb.newTextBaseSHA1Checksum != null) {
contentState = SVNStatusType.CHANGED;
} else {
contentState = SVNStatusType.UNCHANGED;
}
}
if (installPristine) {
boolean recordFileInfo = installFrom == null;
SVNSkel wi = myWCContext.wqBuildFileInstall(fb.localAbsolutePath, installFrom, myIsUseCommitTimes, recordFileInfo);
allWorkItems = myWCContext.wqMerge(allWorkItems, wi);
} else if (lockState == SVNStatusType.LOCK_UNLOCKED && !fb.obstructionFound) {
SVNSkel wi = myWCContext.wqBuildSyncFileFlags(fb.localAbsolutePath);
allWorkItems = myWCContext.wqMerge(allWorkItems, wi);
}
if (!installPristine && contentState == SVNStatusType.UNCHANGED) {
keepRecordedInfo = true;
}
if (installFrom != null && !fb.localAbsolutePath.equals(installFrom)) {
SVNSkel wi = myWCContext.wqBuildFileRemove(fb.localAbsolutePath, installFrom);
allWorkItems = myWCContext.wqMerge(allWorkItems, wi);
}
} else {
SVNProperties fakeActualProperties;
if (fb.addingFile) {
fakeActualProperties = new SVNProperties();
} else {
fakeActualProperties = currentBaseProps;
}
MergePropertiesInfo info = new MergePropertiesInfo();
info.newActualProperties = newActualProps;
info.newBaseProperties = newBaseProps;
info.conflictSkel = conflictSkel;
info = myWCContext.mergeProperties3(info, fb.localAbsolutePath, null, currentBaseProps, fakeActualProperties, regularPropChanges);
conflictSkel = info.conflictSkel;
newActualProps = info.newActualProperties;
newBaseProps = info.newBaseProperties;
propState[0] = info.mergeOutcome;
allWorkItems = myWCContext.wqMerge(allWorkItems, info.workItems);
if (fb.newTextBaseSHA1Checksum != null) {
contentState = SVNStatusType.CHANGED;
} else {
contentState = SVNStatusType.UNCHANGED;
}
}
SvnChecksum newChecksum = fb.newTextBaseSHA1Checksum;
if (newChecksum == null) {
newChecksum = fb.originalChecksum;
}
if (conflictSkel != null) {
completeConflict(conflictSkel, fb.localAbsolutePath, fb.oldReposRelPath, fb.oldRevision,
fb.newRelativePath, SVNNodeKind.FILE, SVNNodeKind.FILE);
SVNSkel workItem = myWCContext.conflictCreateMarker(conflictSkel, fb.localAbsolutePath);
allWorkItems = myWCContext.wqMerge(allWorkItems, workItem);
}
if (myInheritableProperties != null) {
Map<String, SVNProperties> iprops = myInheritableProperties.get(fb.localAbsolutePath);
if (iprops != null) {
myInheritableProperties.remove(fb.localAbsolutePath);
}
}
if (davProps != null) {
davProps.removeNullValues();
}
Map<String, SVNProperties> iprops = null;
if (myInheritableProperties != null) {
iprops = myInheritableProperties.remove(fb.localAbsolutePath);
}
myWCContext.getDb().addBaseFile(fb.localAbsolutePath, fb.newRelativePath, myReposRootURL, myReposUuid,
myTargetRevision, newBaseProps, fb.changedRevison, fb.changedDate, fb.changedAuthor, newChecksum,
davProps != null && !davProps.isEmpty() ? davProps : null, fb.addExisted && fb.addingFile,
!fb.shadowed && newBaseProps != null, newActualProps, keepRecordedInfo, fb.shadowed && fb.obstructionFound,
iprops, conflictSkel, allWorkItems);
if (conflictSkel != null && myConflictHandler != null) {
myWCContext.invokeConflictResolver(fb.localAbsolutePath, conflictSkel, myConflictHandler, ISVNCanceller.NULL);
}
if (fb.directoryBaton.notPresentFiles != null) {
fb.directoryBaton.notPresentFiles.remove(fb.name);
}
if (myWCContext.getEventHandler() != null && !fb.alreadyNotified
&& (fb.edited || lockState == SVNStatusType.LOCK_UNLOCKED)) {
SVNEventAction action = SVNEventAction.UPDATE_UPDATE;
if (fb.edited) {
if (fb.shadowed || fb.editObstructed) {
action = fb.addingFile ? SVNEventAction.UPDATE_SHADOWED_ADD : SVNEventAction.UPDATE_SHADOWED_UPDATE;
} else if (fb.obstructionFound || fb.addExisted) {
if (contentState != SVNStatusType.CONFLICTED) {
action = SVNEventAction.UPDATE_EXISTS;
}
} else if (fb.addingFile) {
action = SVNEventAction.UPDATE_ADD;
}
} else {
assert lockState == SVNStatusType.LOCK_UNLOCKED;
action = SVNEventAction.UPDATE_BROKEN_LOCK;
}
String mimeType = myWCContext.getProperty(fb.localAbsolutePath, SVNProperty.MIME_TYPE);
SVNEvent event = SVNEventFactory.createSVNEvent(fb.localAbsolutePath, SVNNodeKind.FILE, mimeType, myTargetRevision, contentState, propState[0], lockState, action, null, null, null);
SVNURL url = fb.getURL();
event.setPreviousRevision(fb.oldRevision);
event.setURL(url);
myWCContext.getEventHandler().handleEvent(event, 0);
}
maybeBumpDirInfo(fb.bumpInfo);
}
public SVNCommitInfo closeEdit() throws SVNException {
if (!rootOpened && ("".equals(myTargetBasename) || myTargetBasename == null)) {
myWCContext.getDb().opSetBaseIncompleteTemp(myAnchorAbspath, false);
}
if (!myIsTargetDeleted) {
myWCContext.getDb().opBumpRevisionPostUpdate(myTargetAbspath , myRequestedDepth, mySwitchRelpath, myReposRootURL, myReposUuid, myTargetRevision, mySkippedTrees, myInheritableProperties, myWCContext.getEventHandler());
if (myTargetBasename == null || "".equals(myTargetBasename)) {
SVNWCDbStatus status = null;
boolean error = false;
try {
status = myWCContext.getDb().getBaseInfo(myTargetAbspath, BaseInfoField.status).status;
} catch (SVNException e) {
if (e.getErrorMessage().getErrorCode() != SVNErrorCode.WC_PATH_NOT_FOUND) {
throw e;
}
error = true;
}
if (!error && status == SVNWCDbStatus.Excluded) {
myWCContext.getDb().removeBase(myTargetAbspath);
}
}
}
myWCContext.wqRun(myAnchorAbspath);
return null;
}
public void abortEdit() throws SVNException {
}
public void applyTextDelta(String path, String expectedChecksum) throws SVNException {
FileBaton fb = myCurrentFile;
if (fb.skipThis) {
return;
}
fb.markEdited();
SvnChecksum expectedBaseChecksum = expectedChecksum != null ? new SvnChecksum(SvnChecksum.Kind.md5, expectedChecksum) : null;
SvnChecksum recordedBaseChecksum = fb.originalChecksum;
if (recordedBaseChecksum != null && expectedBaseChecksum != null && recordedBaseChecksum.getKind() != SvnChecksum.Kind.md5) {
recordedBaseChecksum = myWCContext.getDb().getPristineMD5(myAnchorAbspath, recordedBaseChecksum);
}
if (recordedBaseChecksum != null && expectedBaseChecksum != null && !expectedBaseChecksum.equals(recordedBaseChecksum)) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.WC_CORRUPT_TEXT_BASE, "Checksum mismatch for ''{0}'':\n " + " expected: ''{1}''\n" + " recorded: ''{2}''\n",
new Object[] {
fb.localAbsolutePath, expectedBaseChecksum, recordedBaseChecksum
});
SVNErrorManager.error(err, SVNLogType.WC);
return;
}
InputStream source;
if (!fb.addingFile) {
source = myWCContext.getDb().readPristine(fb.localAbsolutePath, fb.originalChecksum);
if (source == null) {
source = SVNFileUtil.DUMMY_IN;
}
} else {
source = SVNFileUtil.DUMMY_IN;
}
if (recordedBaseChecksum == null) {
recordedBaseChecksum = expectedBaseChecksum;
}
if (recordedBaseChecksum != null) {
fb.expectedSourceChecksum = new SvnChecksum(recordedBaseChecksum.getKind(), recordedBaseChecksum.getDigest());
if (source != SVNFileUtil.DUMMY_IN) {
source = new SVNChecksumInputStream(source, SVNChecksumInputStream.MD5_ALGORITHM);
fb.sourceChecksumStream = (SVNChecksumInputStream) source;
}
}
WritableBaseInfo openWritableBase = myWCContext.openWritableBase(fb.localAbsolutePath, false, true);
OutputStream target = openWritableBase.stream;
fb.newTextBaseTmpAbsPath = openWritableBase.tempBaseAbspath;
myDeltaProcessor.applyTextDelta(source, target, true);
fb.newTextBaseSHA1ChecksumStream = openWritableBase.sha1ChecksumStream;
}
public OutputStream textDeltaChunk(String path, SVNDiffWindow diffWindow) throws SVNException {
if (myCurrentFile.skipThis) {
return SVNFileUtil.DUMMY_OUT;
}
try {
myDeltaProcessor.textDeltaChunk(diffWindow);
} catch (SVNException svne) {
myDeltaProcessor.textDeltaEnd();
SVNFileUtil.deleteFile(myCurrentFile.newTextBaseTmpAbsPath);
myCurrentFile.newTextBaseTmpAbsPath = null;
throw svne;
}
return SVNFileUtil.DUMMY_OUT;
}
public void textDeltaEnd(String path) throws SVNException {
if (myCurrentFile.skipThis) {
return;
}
myCurrentFile.newTextBaseMD5Digest = myDeltaProcessor.textDeltaEnd();
if (myCurrentFile.newTextBaseSHA1ChecksumStream != null) {
myCurrentFile.newTextBaseSHA1Checksum = new SvnChecksum(SvnChecksum.Kind.sha1, myCurrentFile.newTextBaseSHA1ChecksumStream.getDigest());
}
if (myCurrentFile.expectedSourceChecksum != null && myCurrentFile.expectedSourceChecksum.getKind() == SvnChecksum.Kind.md5) {
String actualSourceChecksum = myCurrentFile.sourceChecksumStream != null ? myCurrentFile.sourceChecksumStream.getDigest() : null;
if (!myCurrentFile.expectedSourceChecksum.getDigest().equals(actualSourceChecksum)) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.WC_CORRUPT_TEXT_BASE, "Checksum mismatch while updating ''{0}''; expected: ''{1}'', actual: ''{2}''", new Object[] {
myCurrentFile.localAbsolutePath, myCurrentFile.expectedSourceChecksum.getDigest(), actualSourceChecksum
});
SVNErrorManager.error(err, SVNLogType.WC);
}
}
if (myCurrentFile.newTextBaseTmpAbsPath != null && myCurrentFile.newTextBaseSHA1Checksum != null && myCurrentFile.newTextBaseMD5Digest != null) {
myWCContext.getDb().installPristine(myCurrentFile.newTextBaseTmpAbsPath, myCurrentFile.newTextBaseSHA1Checksum,
new SvnChecksum(SvnChecksum.Kind.md5, myCurrentFile.newTextBaseMD5Digest));
}
if (myCurrentFile.originalChecksum != null && myCurrentFile.newTextBaseSHA1Checksum != null && myCurrentFile.originalChecksum.equals(myCurrentFile.newTextBaseSHA1Checksum)) {
myCurrentFile.newTextBaseSHA1Checksum = null;
}
}
private static class BumpDirectoryInfo {
private int refCount;
private BumpDirectoryInfo parent;
}
private class DirectoryBaton {
private String name;
private File localAbsolutePath;
private File newRelativePath;
private long oldRevision;
private File oldReposRelPath;
DirectoryBaton parentBaton;
private boolean skipThis;
private boolean alreadyNotified;
private boolean addingDir;
private boolean shadowed;
private boolean editedObstructed;
private long changedRevsion;
private SVNDate changedDate;
private String changedAuthor;
private Map<String, SVNSkel> deletionConflicts;
private Set<String> notPresentFiles;
private boolean obstructionFound;
private boolean addExisted;
private SVNProperties propChanges;
private boolean edited;
private SVNSkel editConflict;
private BumpDirectoryInfo bumpInfo;
private SVNDepth ambientDepth;
private boolean wasIncomplete;
public void markEdited() throws SVNException {
if (edited) {
return;
}
if (parentBaton != null) {
parentBaton.markEdited();
}
edited = true;
if (editConflict != null) {
completeConflict(editConflict, localAbsolutePath, oldReposRelPath, oldRevision, newRelativePath, SVNNodeKind.DIR, SVNNodeKind.DIR);
myWCContext.getDb().opMarkConflict(localAbsolutePath, editConflict, null);
doNotification(localAbsolutePath, SVNNodeKind.DIR, SVNEventAction.TREE_CONFLICT, getURL(), getPreviousURL());
alreadyNotified = true;
}
}
public SVNURL getURL() throws SVNException {
if (newRelativePath != null) {
return SVNWCUtils.join(myReposRootURL, newRelativePath);
}
return null;
}
public SVNURL getPreviousURL() throws SVNException {
if (oldReposRelPath != null) {
return SVNWCUtils.join(myReposRootURL, oldReposRelPath);
}
return null;
}
}
private class FileBaton {
private String name;
private File localAbsolutePath;
private File newRelativePath;
private long oldRevision;
private File oldReposRelPath;
private DirectoryBaton directoryBaton;
private boolean skipThis;
private boolean alreadyNotified;
private boolean addingFile;
private boolean obstructionFound;
private boolean addExisted;
private boolean shadowed;
private boolean editObstructed;
private long changedRevison;
private SVNDate changedDate;
private String changedAuthor;
private SvnChecksum newTextBaseMd5Checksum;
private SvnChecksum newTextBaseSha1Checksum;
private SvnChecksum originalChecksum;
private SVNProperties propChanges;
private boolean localPropMods;
private BumpDirectoryInfo bumpInfo;
private boolean edited;
private SVNSkel editConflict;
public void markEdited() throws SVNException {
if (edited) {
return;
}
if (directoryBaton != null) {
directoryBaton.markEdited();
}
edited = true;
if (editConflict != null) {
completeConflict(editConflict, localAbsolutePath, oldReposRelPath, oldRevision, newRelativePath, SVNNodeKind.FILE, SVNNodeKind.FILE);
myWCContext.getDb().opMarkConflict(localAbsolutePath, editConflict, null);
doNotification(localAbsolutePath, SVNNodeKind.FILE, SVNEventAction.TREE_CONFLICT, getURL(), getPreviousURL());
alreadyNotified = true;
}
}
public SVNURL getURL() throws SVNException {
if (newRelativePath != null) {
return SVNWCUtils.join(myReposRootURL, newRelativePath);
}
return null;
}
public SVNURL getPreviousURL() throws SVNException {
if (oldReposRelPath != null) {
return SVNWCUtils.join(myReposRootURL, oldReposRelPath);
}
return null;
}
// delta handling
File newTextBaseTmpAbsPath;
SVNChecksumInputStream sourceChecksumStream;
SVNChecksumOutputStream newTextBaseSHA1ChecksumStream;
SvnChecksum expectedSourceChecksum;
String newTextBaseMD5Digest;
public SvnChecksum newTextBaseSHA1Checksum;
}
private DirectoryBaton makeDirectoryBaton(String path, DirectoryBaton parent, boolean adding) throws SVNException {
DirectoryBaton d = new DirectoryBaton();
if (path != null) {
d.name = SVNPathUtil.tail(path);
d.localAbsolutePath = SVNFileUtil.createFilePath(parent.localAbsolutePath, d.name);
} else {
d.name = null;
d.localAbsolutePath = myAnchorAbspath;
}
if (mySwitchRelpath != null) {
if (parent == null ) {
if ("".equals(myTargetBasename) || myTargetBasename == null) {
d.newRelativePath = mySwitchRelpath;
} else {
d.newRelativePath = myWCContext.getDb().scanBaseRepository(d.localAbsolutePath, RepositoryInfoField.relPath).relPath;
}
} else {
if (parent.parentBaton ==null && myTargetBasename.equals(d.name)) {
d.newRelativePath = mySwitchRelpath;
} else {
d.newRelativePath = SVNFileUtil.createFilePath(parent.newRelativePath, d.name);
}
}
} else {
if (adding) {
d.newRelativePath = SVNFileUtil.createFilePath(parent.newRelativePath, d.name);
} else {
d.newRelativePath = myWCContext.getDb().scanBaseRepository(d.localAbsolutePath, RepositoryInfoField.relPath).relPath;
}
}
BumpDirectoryInfo bdi = new BumpDirectoryInfo();
bdi.parent = parent != null ? parent.bumpInfo : null;
bdi.refCount = 1;
if (parent != null) {
bdi.parent.refCount++;
}
d.parentBaton = parent;
d.bumpInfo = bdi;
d.oldRevision = -1;
d.addingDir = adding;
d.changedRevsion = -1;
d.notPresentFiles = new HashSet<String>();
if (parent != null) {
d.skipThis = parent.skipThis;
d.shadowed = parent.shadowed || parent.editedObstructed;
}
d.ambientDepth = SVNDepth.UNKNOWN;
d.propChanges = new SVNProperties();
return d;
}
private FileBaton makeFileBaton(DirectoryBaton parent, String path, boolean adding) throws SVNException {
FileBaton f = new FileBaton();
f.name = SVNPathUtil.tail(path);
f.oldRevision = -1;
f.localAbsolutePath = SVNFileUtil.createFilePath(parent.localAbsolutePath, f.name);
if (mySwitchRelpath != null) {
if (parent.parentBaton == null && myTargetBasename != null && f.name.equals(myTargetBasename)) {
f.newRelativePath = mySwitchRelpath;
} else {
f.newRelativePath = SVNFileUtil.createFilePath(parent.newRelativePath, f.name);
}
} else {
if (adding) {
f.newRelativePath = SVNFileUtil.createFilePath(parent.newRelativePath, f.name);
} else {
f.newRelativePath = myWCContext.getDb().scanBaseRepository(f.localAbsolutePath, RepositoryInfoField.relPath).relPath;
}
}
f.bumpInfo = parent.bumpInfo;
f.addingFile = adding;
f.skipThis = parent.skipThis;
f.shadowed = parent.shadowed | parent.editedObstructed;
f.directoryBaton = parent;
f.changedRevison = -1;
f.bumpInfo.refCount++;
f.propChanges = new SVNProperties();
return f;
}
private static boolean isNodePresent(SVNWCDbStatus status) {
return status != SVNWCDbStatus.ServerExcluded && status != SVNWCDbStatus.Excluded && status != SVNWCDbStatus.NotPresent;
}
private SVNTreeConflictDescription createTreeConflict(File localAbspath, SVNConflictReason reason, SVNConflictAction action, SVNNodeKind theirNodeKind, File theirRelpath) throws SVNException {
assert (reason != null);
File leftReposRelpath;
long leftRevision;
SVNNodeKind leftKind = null;
File addedReposRelpath = null;
SVNURL reposRootUrl;
if (reason == SVNConflictReason.ADDED) {
leftKind = SVNNodeKind.NONE;
leftRevision = SVNWCContext.INVALID_REVNUM;
leftReposRelpath = null;
WCDbAdditionInfo scanAddition = myWCContext.getDb().scanAddition(localAbspath, AdditionInfoField.status, AdditionInfoField.reposRelPath, AdditionInfoField.reposRootUrl);
SVNWCDbStatus addedStatus = scanAddition.status;
addedReposRelpath = scanAddition.reposRelPath;
reposRootUrl = scanAddition.reposRootUrl;
assert (addedStatus == SVNWCDbStatus.Added || addedStatus == SVNWCDbStatus.Copied || addedStatus == SVNWCDbStatus.MovedHere);
} else if (reason == SVNConflictReason.UNVERSIONED) {
leftKind = SVNNodeKind.NONE;
leftRevision = SVNWCContext.INVALID_REVNUM;
leftReposRelpath = null;
reposRootUrl = myReposRootURL;
} else {
assert (reason == SVNConflictReason.EDITED || reason == SVNConflictReason.DELETED || reason == SVNConflictReason.REPLACED || reason == SVNConflictReason.OBSTRUCTED);
WCDbBaseInfo baseInfo = myWCContext.getDb().getBaseInfo(localAbspath, BaseInfoField.kind, BaseInfoField.revision, BaseInfoField.reposRelPath, BaseInfoField.reposRootUrl);
SVNWCDbKind baseKind = baseInfo.kind;
leftRevision = baseInfo.revision;
leftReposRelpath = baseInfo.reposRelPath;
reposRootUrl = baseInfo.reposRootUrl;
if (baseKind == SVNWCDbKind.File || baseKind == SVNWCDbKind.Symlink)
leftKind = SVNNodeKind.FILE;
else if (baseKind == SVNWCDbKind.Dir)
leftKind = SVNNodeKind.DIR;
else {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.ASSERTION_FAIL), SVNLogType.WC);
}
}
assert (reposRootUrl.equals(myReposRootURL));
File rightReposRelpath;
if (mySwitchRelpath != null) {
if (theirRelpath != null) {
rightReposRelpath = theirRelpath;
} else {
rightReposRelpath = mySwitchRelpath;
rightReposRelpath = SVNFileUtil.createFilePath(rightReposRelpath.getPath() + "_THIS_IS_INCOMPLETE");
}
} else {
rightReposRelpath = (reason == SVNConflictReason.ADDED ? addedReposRelpath : leftReposRelpath);
if (rightReposRelpath == null) {
rightReposRelpath = theirRelpath;
}
}
assert (rightReposRelpath != null);
SVNNodeKind conflictNodeKind = (action == SVNConflictAction.DELETE ? leftKind : theirNodeKind);
assert (conflictNodeKind == SVNNodeKind.FILE || conflictNodeKind == SVNNodeKind.DIR);
SVNConflictVersion srcLeftVersion;
if (leftReposRelpath == null) {
srcLeftVersion = null;
} else {
srcLeftVersion = new SVNConflictVersion(reposRootUrl, leftReposRelpath.getPath(), leftRevision, leftKind);
}
SVNConflictVersion srcRightVersion = new SVNConflictVersion(reposRootUrl, rightReposRelpath.getPath(), myTargetRevision, theirNodeKind);
return new SVNTreeConflictDescription(localAbspath, conflictNodeKind, action, reason, mySwitchRelpath != null ? SVNOperation.SWITCH : SVNOperation.UPDATE, srcLeftVersion, srcRightVersion);
}
private void maybeBumpDirInfo(BumpDirectoryInfo bdi) throws SVNException {
while (bdi != null) {
if (--bdi.refCount > 0) {
return;
}
// myWcContext.getDb().opSetBaseIncompleteTemp(bdi.absPath, false);
bdi = bdi.parent;
}
return;
}
public static class AccumulatedChangeInfo {
public long changedRev;
public SVNDate changedDate;
public String changedAuthor;
}
public static AccumulatedChangeInfo accumulateLastChange(File localAbspath, SVNProperties entryProps) throws SVNException {
AccumulatedChangeInfo info = new AccumulatedChangeInfo();
info.changedRev = SVNWCContext.INVALID_REVNUM;
info.changedDate = null;
info.changedAuthor = null;
if (entryProps != null) {
for (Iterator<?> i = entryProps.nameSet().iterator(); i.hasNext();) {
String propertyName = (String) i.next();
String propertyValue = entryProps.getStringValue(propertyName);
if (propertyValue == null) {
continue;
}
if (SVNProperty.LAST_AUTHOR.equals(propertyName)) {
info.changedAuthor = propertyValue;
} else if (SVNProperty.COMMITTED_REVISION.equals(propertyName)) {
info.changedRev = Long.valueOf(propertyValue);
} else if (SVNProperty.COMMITTED_DATE.equals(propertyName)) {
info.changedDate = SVNDate.parseDate(propertyValue);
}
}
}
return info;
}
private static class MergeFileInfo {
public SVNSkel workItem;
public boolean installPristine;
public File installFrom;
public SVNStatusType contentState;
public SVNSkel conflictSkel;
}
public static MergeInfo performFileMerge(MergeInfo mergeInfo, SVNWCContext context, File localAbsPath, File wriAbsPath, SvnChecksum newChecksum, SvnChecksum originalChecksum,
SVNProperties actualProperties, String[] extPatterns,
long oldRevision, long targetRevision, SVNProperties propChanges) throws SVNException {
File mergeLeft = null;
boolean deleteLeft = false;
File newTextBaseTmpAbsPath = context.getDb().getPristinePath(wriAbsPath, newChecksum);
if (extPatterns != null && extPatterns.length > 0) {
}
if (oldRevision < 0) {
oldRevision = 0;
}
String oldRevStr = String.format(".r%s%s%s", oldRevision, "", "");
String newRevStr = String.format(".r%s%s%s", targetRevision, "", "");
String mineStr = String.format(".mine%s%s", "", "");
if (originalChecksum == null) {
File tmpDir = context.getDb().getWCRootTempDir(wriAbsPath);
mergeLeft = SVNFileUtil.createUniqueFile(tmpDir, "file", "tmp", false);
deleteLeft = true;
} else {
mergeLeft = context.getDb().getPristinePath(wriAbsPath, originalChecksum);
}
mergeInfo = context.merge(mergeInfo.workItems, mergeInfo.conflictSkel, mergeLeft, newTextBaseTmpAbsPath, localAbsPath, wriAbsPath,
oldRevStr, newRevStr, mineStr, actualProperties, false, null, propChanges);
mergeInfo.foundTextConflict = mergeInfo.mergeOutcome == SVNStatusType.CONFLICTED;
if (deleteLeft) {
SVNSkel workItem = context.wqBuildFileRemove(wriAbsPath, mergeLeft);
context.wqMerge(mergeInfo.workItems, workItem);
}
return mergeInfo;
}
private MergeFileInfo mergeFile(FileBaton fb, MergeFileInfo mergeFileInfo, SVNProperties actualProps, SVNDate lastChangedDate) throws SVNException {
DirectoryBaton pb = fb.directoryBaton;
boolean isLocallyModified;
boolean magicPropsChanged= false;
boolean foundTextConflict = false;
assert !fb.shadowed && !fb.obstructionFound && !fb.editObstructed;
if (mergeFileInfo == null) {
mergeFileInfo = new MergeFileInfo();
}
mergeFileInfo.workItem = null;
mergeFileInfo.installPristine = false;
mergeFileInfo.contentState = SVNStatusType.UNCHANGED;
mergeFileInfo.installFrom = null;
if (fb.addingFile && !fb.addExisted) {
isLocallyModified = false;
} else {
isLocallyModified = myWCContext.isTextModified(fb.localAbsolutePath, false);
}
SVNProperties propChanges = fb.propChanges;
if (!isLocallyModified && fb.newTextBaseSHA1Checksum != null) {
mergeFileInfo.installPristine = true;
} else if (fb.newTextBaseSHA1Checksum != null) {
MergeInfo mergeInfo = new MergeInfo();
mergeInfo.conflictSkel = mergeFileInfo.conflictSkel;
mergeInfo.workItems = mergeFileInfo.workItem;
mergeInfo = performFileMerge(mergeInfo, myWCContext,
fb.localAbsolutePath,
pb.localAbsolutePath,
fb.newTextBaseSHA1Checksum,
fb.addExisted ? null : fb.originalChecksum,
actualProps,
myExtensionPatterns,
fb.oldRevision,
myTargetRevision,
propChanges);
mergeFileInfo.workItem = myWCContext.wqMerge(mergeFileInfo.workItem, mergeInfo.workItems);
mergeFileInfo.contentState = mergeInfo.mergeOutcome;
mergeFileInfo.conflictSkel = mergeInfo.conflictSkel;
foundTextConflict = mergeInfo.foundTextConflict;
} else {
magicPropsChanged = myWCContext.hasMagicProperty(propChanges);
TranslateInfo translateInfo = myWCContext.getTranslateInfo(fb.localAbsolutePath, actualProps, true, false, false, true, false);
if (magicPropsChanged || (translateInfo.keywords != null && !translateInfo.keywords.isEmpty())) {
if (isLocallyModified) {
File tmpText = null;
tmpText = myWCContext.getTranslatedFile(fb.localAbsolutePath, fb.localAbsolutePath, true, true, false, false, false);
mergeFileInfo.installPristine = true;
mergeFileInfo.installFrom = tmpText;
} else {
mergeFileInfo.installPristine = true;
}
}
}
if (foundTextConflict) {
mergeFileInfo.contentState = SVNStatusType.CONFLICTED;
} else if (fb.newTextBaseSHA1Checksum != null) {
if (isLocallyModified) {
mergeFileInfo.contentState = SVNStatusType.MERGED;
} else {
mergeFileInfo.contentState = SVNStatusType.CHANGED;
}
} else {
mergeFileInfo.contentState = SVNStatusType.UNCHANGED;
}
return mergeFileInfo;
}
public void completeConflict(SVNSkel conflict,
File localAbsPath, File oldReposRelPath,
long oldRevision, File newReposRelPath,
SVNNodeKind localKind, SVNNodeKind targetKind) throws SVNException {
SVNConflictVersion originalVersion;
SVNConflictVersion targetVersion;
if (conflict == null) {
return;
}
boolean isComplete = SvnWcDbConflicts.isConflictSkelComplete(conflict);
if (isComplete) {
return;
}
if (oldReposRelPath != null) {
originalVersion = new SVNConflictVersion(myReposRootURL, SVNFileUtil.getFilePath(oldReposRelPath), oldRevision, localKind);
} else {
originalVersion = null;
}
if (newReposRelPath != null) {
targetVersion = new SVNConflictVersion(myReposRootURL, SVNFileUtil.getFilePath(newReposRelPath), myTargetRevision, targetKind);
} else {
targetVersion = null;
}
if (mySwitchRelpath != null) {
SvnWcDbConflicts.conflictSkelOpSwitch(conflict, originalVersion, targetVersion);
} else {
SvnWcDbConflicts.conflictSkelOpUpdate(conflict, originalVersion, targetVersion);
}
}
}