/* * ==================================================================== * Copyright (c) 2004-2012 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.wc; import java.io.File; import java.util.Iterator; import java.util.Map; import org.tmatesoft.svn.core.SVNCancelException; import org.tmatesoft.svn.core.SVNErrorCode; import org.tmatesoft.svn.core.SVNErrorMessage; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNNodeKind; import org.tmatesoft.svn.core.SVNProperties; import org.tmatesoft.svn.core.SVNProperty; import org.tmatesoft.svn.core.SVNPropertyValue; import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.internal.util.SVNHashMap; import org.tmatesoft.svn.core.internal.util.SVNPathUtil; import org.tmatesoft.svn.core.internal.wc.SVNMergeDriver.MergeSource; import org.tmatesoft.svn.core.internal.wc.admin.SVNAdminArea; import org.tmatesoft.svn.core.internal.wc.admin.SVNEntry; import org.tmatesoft.svn.core.internal.wc.admin.SVNWCAccess; import org.tmatesoft.svn.core.io.SVNRepository; import org.tmatesoft.svn.core.wc.ISVNEventHandler; import org.tmatesoft.svn.core.wc.SVNConflictAction; import org.tmatesoft.svn.core.wc.SVNConflictReason; import org.tmatesoft.svn.core.wc.SVNDiffOptions; import org.tmatesoft.svn.core.wc.SVNEvent; import org.tmatesoft.svn.core.wc.SVNStatusType; import org.tmatesoft.svn.core.wc.SVNTreeConflictDescription; import org.tmatesoft.svn.util.SVNLogType; /** * @version 1.3 * @author TMate Software Ltd. */ public class SVNMergeCallback extends AbstractDiffCallback { protected boolean myIsDryRun; protected SVNURL myURL; protected boolean myIsAddNecessitatedMerge; protected String myAddedPath = null; protected boolean myIsForce; protected SVNDiffOptions myDiffOptions; protected Map myConflictedPaths; protected SVNMergeDriver myMergeDriver; public SVNMergeCallback(SVNAdminArea adminArea, SVNURL url, boolean force, boolean dryRun, SVNDiffOptions options, Map conflictedPathsGetter, SVNMergeDriver mergeDriver) { super(adminArea); myURL = url; myIsDryRun = dryRun; myIsForce = force; myDiffOptions = options; myConflictedPaths = conflictedPathsGetter; myMergeDriver = mergeDriver; } public File createTempDirectory() throws SVNException { return SVNFileUtil.createTempDirectory("merge"); } public boolean isDiffUnversioned() { return false; } public boolean isDiffCopiedAsAdded() { return false; } public Map getConflictedPaths() { return myConflictedPaths; } public SVNStatusType propertiesChanged(String path, SVNProperties originalProperties, SVNProperties diff, boolean[] isTreeConflicted) throws SVNException { setIsConflicted(isTreeConflicted, false); SVNStatusType obstructedStatus = getStatusForObstructedOrMissing(path); if (obstructedStatus != SVNStatusType.INAPPLICABLE) { return obstructedStatus; } SVNProperties regularProps = new SVNProperties(); categorizeProperties(diff, regularProps, null, null); if (regularProps.isEmpty()) { return SVNStatusType.UNKNOWN; } try { File file = getFile(path); SVNWCAccess wcAccess = getWCAccess(); if (wcAccess.getAdminArea(file) == null) { wcAccess.probeTry(file, true, SVNWCAccess.INFINITE_DEPTH); } MergeSource mergeSource = myMergeDriver.getCurrentMergeSource(); if (mergeSource.getRevision1() < mergeSource.getRevision2() || !myMergeDriver.myAreSourcesAncestral) { SVNProperties filteredProps = myMergeDriver.filterSelfReferentialMergeInfo(regularProps, file); if (filteredProps != null) { regularProps = filteredProps; } } SVNStatusType status = SVNPropertiesManager.mergeProperties(getWCAccess(), file, originalProperties, regularProps, false, myIsDryRun); if (!myIsDryRun) { for (Iterator propsIter = regularProps.nameSet().iterator(); propsIter.hasNext();) { String propName = (String) propsIter.next(); SVNPropertyValue propValue = regularProps.getSVNPropertyValue(propName); if (SVNProperty.MERGE_INFO.equals(propName)) { SVNPropertyValue mergeInfoProp = originalProperties.getSVNPropertyValue(SVNProperty.MERGE_INFO); if (mergeInfoProp == null && propValue != null) { myMergeDriver.addPathWithNewMergeInfo(file); } else if (mergeInfoProp != null && propValue == null) { myMergeDriver.addPathWithDeletedMergeInfo(file); } } } } return status; } catch (SVNException e) { if (e.getErrorMessage().getErrorCode() == SVNErrorCode.UNVERSIONED_RESOURCE || e.getErrorMessage().getErrorCode() == SVNErrorCode.ENTRY_NOT_FOUND) { setIsConflicted(isTreeConflicted, true); return SVNStatusType.MISSING; } throw e; } } public SVNStatusType directoryAdded(String path, long revision, boolean[] isTreeConflicted) throws SVNException { setIsConflicted(isTreeConflicted, false); File mergedFile = getFile(path); SVNAdminArea dir = retrieve(mergedFile.getParentFile(), true); if (dir == null) { if (myIsDryRun && myAddedPath != null && SVNPathUtil.isAncestor(myAddedPath, path)) { return SVNStatusType.CHANGED; } return SVNStatusType.MISSING; } SVNURL copyFromURL = null; long copyFromRevision = SVNRepository.INVALID_REVISION; if (myMergeDriver.myIsSameRepository) { copyFromURL = myURL.appendPath(path, false); copyFromRevision = revision; // TODO protocol } SVNFileType fileType = SVNFileType.getType(mergedFile); SVNStatusType obstructedStatus = getStatusForObstructedOrMissing(path); if (obstructedStatus == SVNStatusType.MISSING || (obstructedStatus == SVNStatusType.OBSTRUCTED && (fileType == SVNFileType.FILE || fileType == SVNFileType.SYMLINK))) { return obstructedStatus; } if (fileType == SVNFileType.NONE) { if (myIsDryRun) { myAddedPath = path; } else { if (!mergedFile.mkdirs()) { if (SVNFileType.getType(mergedFile) != SVNFileType.DIRECTORY) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "Cannot create directory ''{0}''", mergedFile); SVNErrorManager.error(err, SVNLogType.DEFAULT); } } ISVNEventHandler oldEventHandler = dir.getWCAccess().getEventHandler(); dir.getWCAccess().setEventHandler(null); SVNWCManager.add(mergedFile, dir, copyFromURL, copyFromRevision, null); dir.getWCAccess().setEventHandler(oldEventHandler); } return SVNStatusType.CHANGED; } else if (fileType == SVNFileType.DIRECTORY) { SVNEntry entry = getWCAccess().getEntry(mergedFile, false); if (entry == null || entry.isScheduledForDeletion()) { if (!myIsDryRun) { ISVNEventHandler oldEventHandler = dir.getWCAccess().getEventHandler(); dir.getWCAccess().setEventHandler(null); SVNWCManager.add(mergedFile, dir, copyFromURL, copyFromRevision, null); dir.getWCAccess().setEventHandler(oldEventHandler); } if (myIsDryRun) { myAddedPath = path; } return SVNStatusType.CHANGED; } if (myIsDryRun && isPathDeleted(path)) { return SVNStatusType.CHANGED; } myMergeDriver.recordTreeConflictOnAdd(mergedFile, dir, SVNNodeKind.DIR, SVNConflictAction.ADD, SVNConflictReason.ADDED); setIsConflicted(isTreeConflicted, true); return SVNStatusType.OBSTRUCTED; } else if (fileType == SVNFileType.FILE || fileType == SVNFileType.SYMLINK) { if (myIsDryRun) { myAddedPath = null; } SVNEntry entry = getWCAccess().getEntry(mergedFile, false); if (entry != null && myIsDryRun && isPathDeleted(path)) { return SVNStatusType.CHANGED; } myMergeDriver.recordTreeConflictOnAdd(mergedFile, dir, SVNNodeKind.DIR, SVNConflictAction.ADD, SVNConflictReason.OBSTRUCTED); setIsConflicted(isTreeConflicted, true); return SVNStatusType.OBSTRUCTED; } if (myIsDryRun) { myAddedPath = null; } return SVNStatusType.UNKNOWN; } public SVNStatusType directoryDeleted(final String path, boolean[] isTreeConflicted) throws SVNException { setIsConflicted(isTreeConflicted, false); final File mergedFile = getFile(path); final SVNAdminArea dir = retrieve(mergedFile.getParentFile(), true); if (dir == null) { return SVNStatusType.MISSING; } SVNEntry entry = getWCAccess().getEntry(mergedFile, true); SVNStatusType obstructedStatus = getStatusForObstructedOrMissing(path); if (obstructedStatus != SVNStatusType.INAPPLICABLE) { return obstructedStatus; } SVNFileType fileType = SVNFileType.getType(mergedFile); if (fileType == SVNFileType.DIRECTORY) { if (entry != null && !entry.isScheduledForDeletion()) { final ISVNEventHandler oldEventHandler = getWCAccess().getEventHandler(); ISVNEventHandler handler = new ISVNEventHandler() { public void checkCancelled() throws SVNCancelException { oldEventHandler.checkCancelled(); } public void handleEvent(SVNEvent event, double progress) throws SVNException { } }; getWCAccess().setEventHandler(handler); try { delete(mergedFile, myIsForce, myIsDryRun, false); } catch (SVNException e) { myMergeDriver.recordTreeConflict(mergedFile, dir, SVNNodeKind.DIR, SVNConflictAction.DELETE, SVNConflictReason.EDITED); setIsConflicted(isTreeConflicted, true); return SVNStatusType.CONFLICTED; } finally { getWCAccess().setEventHandler(oldEventHandler); } return SVNStatusType.CHANGED; } myMergeDriver.recordTreeConflict(mergedFile, dir, SVNNodeKind.DIR, SVNConflictAction.DELETE, SVNConflictReason.DELETED); setIsConflicted(isTreeConflicted, true); } else if (fileType == SVNFileType.FILE || fileType == SVNFileType.SYMLINK) { return SVNStatusType.OBSTRUCTED; } else if (fileType == SVNFileType.NONE) { myMergeDriver.recordTreeConflict(mergedFile, dir, SVNNodeKind.DIR, SVNConflictAction.DELETE, SVNConflictReason.DELETED); setIsConflicted(isTreeConflicted, true); return SVNStatusType.MISSING; } return SVNStatusType.UNKNOWN; } public void directoryOpened(String path, long revision, boolean[] isTreeConflicted) throws SVNException { setIsConflicted(isTreeConflicted, false); File mergedFile = getFile(path); SVNAdminArea dir = retrieve(mergedFile.getParentFile(), myIsDryRun); if (dir == null) { return; } SVNEntry entry = getWCAccess().getEntry(mergedFile, true); SVNFileType type = SVNFileType.getType(mergedFile); if (entry == null || entry.isScheduledForDeletion()) { myMergeDriver.recordTreeConflict(mergedFile, dir, SVNNodeKind.DIR, SVNConflictAction.EDIT, SVNConflictReason.DELETED); setIsConflicted(isTreeConflicted, true); } else if (entry.isDirectory() && type == SVNFileType.NONE) { myMergeDriver.recordTreeConflict(mergedFile, dir, SVNNodeKind.DIR, SVNConflictAction.EDIT, SVNConflictReason.MISSING); setIsConflicted(isTreeConflicted, true); } else if (entry.isDirectory() && type != SVNFileType.DIRECTORY) { myMergeDriver.recordTreeConflict(mergedFile, dir, SVNNodeKind.DIR, SVNConflictAction.EDIT, SVNConflictReason.OBSTRUCTED); setIsConflicted(isTreeConflicted, true); } else if (type != SVNFileType.DIRECTORY) { // entry of different kind as well, directory has been deleted. myMergeDriver.recordTreeConflict(mergedFile, dir, SVNNodeKind.DIR, SVNConflictAction.EDIT, SVNConflictReason.DELETED); setIsConflicted(isTreeConflicted, true); } } public SVNStatusType[] fileChanged(String path, File file1, File file2, long revision1, long revision2, String mimeType1, String mimeType2, SVNProperties originalProperties, SVNProperties diff, boolean[] isTreeConflicted) throws SVNException { setIsConflicted(isTreeConflicted, false); boolean needsMerge = true; File mergedFile = getFile(path); SVNAdminArea dir = retrieve(mergedFile.getParentFile(), myIsDryRun); if (dir == null) { return new SVNStatusType[] {SVNStatusType.MISSING, SVNStatusType.MISSING}; } SVNStatusType obstructedStatus = getStatusForObstructedOrMissing(path); if (obstructedStatus != SVNStatusType.INAPPLICABLE) { return new SVNStatusType[] { obstructedStatus, SVNStatusType.UNCHANGED }; } SVNStatusType[] result = new SVNStatusType[] {SVNStatusType.UNCHANGED, SVNStatusType.UNCHANGED}; SVNEntry entry = getWCAccess().getEntry(mergedFile, false); SVNFileType fileType = null; if (entry != null) { fileType = SVNFileType.getType(mergedFile); } if (entry == null || (fileType != SVNFileType.FILE && fileType != SVNFileType.SYMLINK)) { myMergeDriver.recordTreeConflict(mergedFile, dir, SVNNodeKind.FILE, SVNConflictAction.EDIT, SVNConflictReason.MISSING); setIsConflicted(isTreeConflicted, true); return new SVNStatusType[] {SVNStatusType.MISSING, SVNStatusType.MISSING}; } if (diff != null && !diff.isEmpty()) { boolean[] isTreeConflicted2 = { false }; result[1] = propertiesChanged(path, originalProperties, diff, isTreeConflicted2); if (isTreeConflicted2[0]) { setIsConflicted(isTreeConflicted, true); return result; } } String name = mergedFile.getName(); if (file1 != null) { boolean textModified = dir.hasTextModifications(name, false); if (!textModified && (SVNProperty.isBinaryMimeType(mimeType1) || SVNProperty.isBinaryMimeType(mimeType2))) { boolean same = SVNFileUtil.compareFiles(!myIsAddNecessitatedMerge ? file1 : file2, mergedFile, null); if (same) { if (!myIsDryRun && !myIsAddNecessitatedMerge) { SVNFileUtil.rename(file2, mergedFile); boolean executable = false; if (diff != null && diff.containsName(SVNProperty.EXECUTABLE)) { executable = diff.getStringValue(SVNProperty.EXECUTABLE) != null; } else { executable = originalProperties != null && originalProperties.getStringValue(SVNProperty.EXECUTABLE) != null; } SVNFileUtil.setExecutable(mergedFile, executable); } result[0] = SVNStatusType.CHANGED; needsMerge = false; } } if (needsMerge) { String localLabel = ".working"; String baseLabel = ".merge-left.r" + revision1; String latestLabel = ".merge-right.r" + revision2; SVNStatusType mergeResult = dir.mergeText(name, file1, file2, null, localLabel, baseLabel, latestLabel, diff, myIsDryRun, myDiffOptions, null); dir.runLogs(); if (mergeResult == SVNStatusType.CONFLICTED || mergeResult == SVNStatusType.CONFLICTED_UNRESOLVED) { result[0] = mergeResult; } else if (textModified && mergeResult != SVNStatusType.UNCHANGED) { result[0] = SVNStatusType.MERGED; } else if (mergeResult == SVNStatusType.MERGED) { result[0] = SVNStatusType.CHANGED; } else if (mergeResult != SVNStatusType.MISSING) { result[0] = SVNStatusType.UNCHANGED; } if (mergeResult == SVNStatusType.CONFLICTED) { if (myConflictedPaths == null) { myConflictedPaths = new SVNHashMap(); } myConflictedPaths.put(path, path); } } // if file is marked as executable } return result; } public SVNStatusType[] fileAdded(String path, File file1, File file2, long revision1, long revision2, String mimeType1, String mimeType2, SVNProperties originalProperties, SVNProperties diff, boolean[] isTreeConflicted) throws SVNException { setIsConflicted(isTreeConflicted, false); SVNStatusType[] result = new SVNStatusType[] {null, SVNStatusType.UNKNOWN}; SVNProperties fileProps = new SVNProperties(originalProperties); for (Iterator propChangesIter = diff.nameSet().iterator(); propChangesIter.hasNext();) { String propName = (String) propChangesIter.next(); if (SVNProperty.isWorkingCopyProperty(propName)) { continue; } if (!myMergeDriver.isSameRepository() && !SVNProperty.isRegularProperty(propName)) { continue; } if (!myMergeDriver.isSameRepository() && SVNProperty.MERGE_INFO.equals(propName)) { continue; } SVNPropertyValue propValue = diff.getSVNPropertyValue(propName); fileProps.put(propName, propValue); } File mergedFile = getFile(path); SVNAdminArea dir = retrieve(mergedFile.getParentFile(), true); if (dir == null) { if (myIsDryRun && myAddedPath != null && SVNPathUtil.isAncestor(myAddedPath, path)) { result[0] = SVNStatusType.CHANGED; if (!fileProps.isEmpty()) { result[1] = SVNStatusType.CHANGED; } } else { result[0] = SVNStatusType.MISSING; } return result; } SVNStatusType obstructedStatus = getStatusForObstructedOrMissing(path); if (obstructedStatus != SVNStatusType.INAPPLICABLE) { return new SVNStatusType[] { obstructedStatus, SVNStatusType.UNCHANGED }; } SVNFileType fileType = SVNFileType.getType(mergedFile); if (fileType == SVNFileType.NONE) { if (!myIsDryRun) { String copyFromURL = null; long copyFromRevision = SVNRepository.INVALID_REVISION; SVNProperties newProps, newBaseProps; File newBaseFile, newFile; if (myMergeDriver.myIsSameRepository) { String targePath = myMergeDriver.myTarget.getAbsolutePath(); String minePath = mergedFile.getAbsolutePath(); String relativePath = SVNPathUtil.getRelativePath(targePath, minePath); if (relativePath != null) { copyFromURL = myURL.appendPath(relativePath, false).toString(); } else { copyFromURL = myURL.toString(); } // TODO compare protocols with dir one. copyFromRevision = revision2; newBaseProps = fileProps; newProps = null; newBaseFile = file2; newFile = null; } else { copyFromURL = null; copyFromRevision = -1; newBaseProps = new SVNProperties(); newProps = fileProps; newBaseFile = null; newFile = file2; } SVNTreeConflictDescription existingConflict = getWCAccess().getTreeConflict(mergedFile); if (existingConflict != null) { myMergeDriver.recordTreeConflictOnAdd(mergedFile, getAdminArea(), SVNNodeKind.FILE, SVNConflictAction.ADD, SVNConflictReason.ADDED); setIsConflicted(isTreeConflicted, true); } else { SVNWCManager.addRepositoryFile(dir, mergedFile.getName(), newFile, newBaseFile, newBaseProps, newProps, copyFromURL, copyFromRevision); } } result[0] = SVNStatusType.CHANGED; if (!fileProps.isEmpty()) { result[1] = SVNStatusType.CHANGED; } } else if (fileType == SVNFileType.DIRECTORY) { myMergeDriver.recordTreeConflictOnAdd(mergedFile, dir, SVNNodeKind.FILE, SVNConflictAction.ADD, SVNConflictReason.OBSTRUCTED); setIsConflicted(isTreeConflicted, true); if (myIsDryRun && isPathDeleted(path)) { result[0] = SVNStatusType.CHANGED; } else { result[0] = SVNStatusType.OBSTRUCTED; } } else if (fileType == SVNFileType.FILE || fileType == SVNFileType.SYMLINK) { if (myIsDryRun && isPathDeleted(path)) { result[0] = SVNStatusType.CHANGED; } else { myMergeDriver.recordTreeConflictOnAdd(mergedFile, dir, SVNNodeKind.FILE, SVNConflictAction.ADD, SVNConflictReason.ADDED); setIsConflicted(isTreeConflicted, true); } } return result; } public SVNStatusType fileDeleted(String path, File file1, File file2, String mimeType1, String mimeType2, SVNProperties originalProperties, boolean[] isTreeConflicted) throws SVNException { setIsConflicted(isTreeConflicted, false); File mergedFile = getFile(path); SVNAdminArea dir = retrieve(mergedFile.getParentFile(), true); if (dir == null) { return SVNStatusType.MISSING; } SVNStatusType obstructedStatus = getStatusForObstructedOrMissing(path); if (obstructedStatus != SVNStatusType.INAPPLICABLE) { return obstructedStatus; } SVNFileType fileType = SVNFileType.getType(mergedFile); if (fileType == SVNFileType.FILE || fileType == SVNFileType.SYMLINK) { if (areFilesTheSame(file1, originalProperties, mergedFile, dir) || myMergeDriver.myIsForce || myMergeDriver.myIsRecordOnly) { ISVNEventHandler oldEventHandler = getWCAccess().getEventHandler(); getWCAccess().setEventHandler(null); try { delete(mergedFile, true, myIsDryRun, false); } catch (SVNException e) { return SVNStatusType.OBSTRUCTED; } finally { getWCAccess().setEventHandler(oldEventHandler); } return SVNStatusType.CHANGED; } myMergeDriver.recordTreeConflict(mergedFile, dir, SVNNodeKind.FILE, SVNConflictAction.DELETE, SVNConflictReason.EDITED); setIsConflicted(isTreeConflicted, true); return SVNStatusType.OBSTRUCTED; } else if (fileType == SVNFileType.DIRECTORY) { myMergeDriver.recordTreeConflict(mergedFile, dir, SVNNodeKind.FILE, SVNConflictAction.DELETE, SVNConflictReason.OBSTRUCTED); setIsConflicted(isTreeConflicted, true); return SVNStatusType.OBSTRUCTED; } else if (fileType == SVNFileType.NONE) { myMergeDriver.recordTreeConflict(mergedFile, dir, SVNNodeKind.FILE, SVNConflictAction.DELETE, SVNConflictReason.DELETED); setIsConflicted(isTreeConflicted, true); return SVNStatusType.MISSING; } return SVNStatusType.UNKNOWN; } public SVNStatusType[] directoryClosed(String path, boolean[] isTreeConflicted) throws SVNException { setIsConflicted(isTreeConflicted, false); return new SVNStatusType[] { SVNStatusType.UNKNOWN, SVNStatusType.UNKNOWN }; } protected File getFile(String path) { return getAdminArea().getFile(path); } protected SVNAdminArea retrieve(File path, boolean lenient) throws SVNException { if (getAdminArea() == null) { return null; } try { return getAdminArea().getWCAccess().retrieve(path); } catch (SVNException e) { if (lenient) { return null; } throw e; } } protected void delete(File path, boolean force, boolean dryRun, boolean keepLocal) throws SVNException { if (!force && !keepLocal) { SVNWCManager.canDelete(path, getWCAccess().getOptions(), getWCAccess()); } SVNAdminArea root = getWCAccess().retrieve(path.getParentFile()); if (!dryRun) { SVNWCManager.delete(getWCAccess(), root, path, !keepLocal, false); } } protected boolean areFilesTheSame(File older, SVNProperties originalProps, File mine, SVNAdminArea adminArea) throws SVNException { SVNProperties workingProps = adminArea.getProperties(mine.getName()).asMap(); if (arePropsTheSame(originalProps, workingProps)) { return !adminArea.hasVersionedFileTextChanges(mine, older, true); } return false; } private SVNStatusType getStatusForObstructedOrMissing(String path) { File file = getFile(path); SVNEntry entry = null; try { entry = getWCAccess().getEntry(file, true); } catch (SVNException svne) { // } if (entry != null && entry.isAbsent()) { return SVNStatusType.MISSING; } SVNNodeKind expectedKind = getWorkingNodeKind(entry, path); SVNNodeKind diskKind = getDiskKind(path); if (entry != null && entry.isDirectory() && entry.isScheduledForDeletion() && diskKind == SVNNodeKind.DIR) { expectedKind = SVNNodeKind.DIR; } if (expectedKind == diskKind) { return SVNStatusType.INAPPLICABLE; } else if (diskKind == SVNNodeKind.NONE) { return SVNStatusType.MISSING; } return SVNStatusType.OBSTRUCTED; } private SVNNodeKind getWorkingNodeKind(SVNEntry entry, String path) { if (entry == null || entry.isScheduledForDeletion() || (myIsDryRun && isPathDeleted(path)) || (entry.isDeleted() && !entry.isScheduledForAddition())) { return SVNNodeKind.NONE; } return entry.getKind(); } private SVNNodeKind getDiskKind(String path) { File file = getFile(path); SVNFileType type = null; type = SVNFileType.getType(file); if (type == SVNFileType.UNKNOWN) { return SVNNodeKind.UNKNOWN; } if (myIsDryRun && isPathDeleted(path)) { return SVNNodeKind.NONE; } return SVNFileType.getNodeKind(type); } private boolean arePropsTheSame(SVNProperties props1, SVNProperties props2) { SVNProperties propsDiff = props2.compareTo(props1); SVNProperties regularPropsDiff = new SVNProperties(); categorizeProperties(propsDiff, regularPropsDiff, null, null); for (Iterator propNamesIter = regularPropsDiff.nameSet().iterator(); propNamesIter.hasNext();) { String propName = (String) propNamesIter.next(); if (!SVNProperty.MERGE_INFO.equals(propName)) { return false; } } return true; } }