/* * ==================================================================== * 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.Map; import org.tmatesoft.svn.core.SVNDepth; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNLock; import org.tmatesoft.svn.core.SVNNodeKind; import org.tmatesoft.svn.core.SVNProperty; import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.internal.util.SVNDate; import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil; import org.tmatesoft.svn.core.internal.util.SVNPathUtil; import org.tmatesoft.svn.core.internal.util.SVNURLUtil; import org.tmatesoft.svn.core.internal.wc.admin.SVNAdminArea; import org.tmatesoft.svn.core.internal.wc.admin.SVNAdminAreaInfo; 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.ISVNStatusHandler; import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc.SVNStatus; import org.tmatesoft.svn.core.wc.SVNStatusType; import org.tmatesoft.svn.core.wc.SVNTreeConflictDescription; /** * @version 1.3 * @author TMate Software Ltd. */ public class SVNStatusUtil { public static SVNRevisionStatus getRevisionStatus(final File wcPath, String trailURL, final boolean committed, ISVNEventHandler eventHandler) throws SVNException { SVNWCAccess wcAccess = null; try { wcAccess = SVNWCAccess.newInstance(eventHandler); SVNAdminAreaInfo anchor = wcAccess.openAnchor(wcPath, false, SVNWCAccess.INFINITE_DEPTH); final long[] minRev = { SVNRepository.INVALID_REVISION }; final long[] maxRev = { SVNRepository.INVALID_REVISION }; final boolean[] isSwitched = { false, false, false }; final boolean[] isModified = { false }; final boolean[] isSparseCheckOut = { false }; final SVNURL[] wcURL = { null }; SVNStatusEditor editor = new SVNStatusEditor(null, wcAccess, anchor, false, true, SVNDepth.INFINITY, new ISVNStatusHandler() { public void handleStatus(SVNStatus status) throws SVNException { SVNEntry entry = status.getEntry(); if (entry == null) { return; } if (status.getContentsStatus() != SVNStatusType.STATUS_ADDED) { long itemRev = committed ? entry.getCommittedRevision() : entry.getRevision(); if (!SVNRevision.isValidRevisionNumber(minRev[0]) || itemRev < minRev[0]) { minRev[0] = itemRev; } if (!SVNRevision.isValidRevisionNumber(maxRev[0]) || itemRev > maxRev[0]) { maxRev[0] = itemRev; } } isSwitched[0] |= status.isSwitched(); isModified[0] |= status.getContentsStatus() != SVNStatusType.STATUS_NORMAL; isModified[0] |= status.getPropertiesStatus() != SVNStatusType.STATUS_NORMAL && status.getPropertiesStatus() != SVNStatusType.STATUS_NONE; isSparseCheckOut[0] |= entry.getDepth() != SVNDepth.INFINITY; if (wcPath != null && wcURL[0] == null && wcPath.equals(status.getFile())) { wcURL[0] = entry.getSVNURL(); } } }); editor.closeEdit(); if (!isSwitched[0] && trailURL != null) { if (wcURL[0] == null) { isSwitched[0] = true; } else { String wcURLStr = wcURL[0].toDecodedString(); if (trailURL.length() > wcURLStr.length() || !wcURLStr.endsWith(trailURL)) { isSwitched[0] = true; } } } return new SVNRevisionStatus(minRev[0], maxRev[0], isSwitched[0], isModified[0], isSparseCheckOut[0]); } finally { wcAccess.close(); } } public static SVNStatus getStatus(File path, SVNWCAccess wcAccess) throws SVNException { SVNEntry entry = null; SVNEntry parentEntry = null; SVNAdminArea adminArea = null; if (wcAccess != null) { entry = wcAccess.getEntry(path, false); adminArea = entry != null ? entry.getAdminArea() : null; } File parentPath = path.getParentFile(); if (entry != null && parentPath != null) { SVNAdminArea parentArea = wcAccess.retrieve(parentPath); if (parentArea != null) { parentEntry = wcAccess.getEntry(parentPath, false); } } return assembleStatus(path, adminArea, entry, parentEntry, SVNNodeKind.UNKNOWN, false, true, false, null, null, wcAccess); } public static SVNStatus assembleStatus(File file, SVNAdminArea dir, SVNEntry entry, SVNEntry parentEntry, SVNNodeKind fileKind, boolean special, boolean reportAll, boolean isIgnored, Map repositoryLocks, SVNURL reposRoot, SVNWCAccess wcAccess) throws SVNException { boolean hasProps = false; boolean isTextModified = false; boolean isPropsModified = false; boolean isLocked = false; boolean isSwitched = false; boolean isSpecial = false; boolean isFileExternal = false; SVNStatusType textStatus = SVNStatusType.STATUS_NORMAL; SVNStatusType propStatus = SVNStatusType.STATUS_NONE; SVNLock repositoryLock = null; if (repositoryLocks != null) { SVNURL url = null; if (entry != null && entry.getSVNURL() != null) { url = entry.getSVNURL(); } else if (parentEntry != null && parentEntry.getSVNURL() != null) { url = parentEntry.getSVNURL().appendPath(file.getName(), false); } if (url != null) { repositoryLock = getLock(repositoryLocks, url, reposRoot); } } if (fileKind == SVNNodeKind.UNKNOWN || fileKind == null) { SVNFileType fileType = SVNFileType.getType(file); fileKind = SVNFileType.getNodeKind(fileType); special = !SVNFileUtil.symlinksSupported() ? false : fileType == SVNFileType.SYMLINK; } int wcFormatNumber = dir != null ? dir.getWorkingCopyFormatVersion() : -1; SVNTreeConflictDescription treeConflict = wcAccess.getTreeConflict(file); if (entry == null) { SVNStatus status = new SVNStatus(null, file, SVNNodeKind.UNKNOWN, SVNRevision.UNDEFINED, SVNRevision.UNDEFINED, null, null, SVNStatusType.STATUS_NONE, SVNStatusType.STATUS_NONE, SVNStatusType.STATUS_NONE, SVNStatusType.STATUS_NONE, false, false, false, false, null, null, null, null, null, SVNRevision.UNDEFINED, repositoryLock, null, null, null, wcFormatNumber, treeConflict); status.setDepth(SVNDepth.UNKNOWN); status.setRemoteStatus(SVNStatusType.STATUS_NONE, SVNStatusType.STATUS_NONE, repositoryLock, SVNNodeKind.NONE); status.setRepositoryRootURL(reposRoot); SVNStatusType text = SVNStatusType.STATUS_NONE; SVNFileType fileType = SVNFileType.getType(file); if (fileType != SVNFileType.NONE) { text = isIgnored ? SVNStatusType.STATUS_IGNORED : SVNStatusType.STATUS_UNVERSIONED; } if (fileType == SVNFileType.NONE && treeConflict != null) { text = SVNStatusType.STATUS_MISSING; } status.setContentsStatus(text); if (status.getURL() != null && status.getRepositoryRelativePath() == null && reposRoot != null) { status.setRepositoryRelativePath(SVNURLUtil.getRelativeURL(reposRoot, status.getURL(), false)); } if (treeConflict != null) { status.setNodeStatus(SVNStatusType.STATUS_CONFLICTED); status.setIsConflicted(true); } return status; } if (entry.getKind() == SVNNodeKind.DIR) { if (fileKind == SVNNodeKind.DIR) { if (wcAccess.isMissing(file)) { textStatus = SVNStatusType.STATUS_OBSTRUCTED; } } else if (fileKind != SVNNodeKind.NONE) { textStatus = SVNStatusType.STATUS_OBSTRUCTED; } } if (entry.getExternalFilePath() != null) { isFileExternal = true; } else if (entry.getSVNURL() != null && parentEntry != null && parentEntry.getSVNURL() != null) { String urlName = SVNPathUtil.tail(entry.getSVNURL().getURIEncodedPath()); if (!SVNEncodingUtil.uriEncode(file.getName()).equals(urlName)) { isSwitched = true; } if (!isSwitched && !entry.getSVNURL().removePathTail().equals(parentEntry.getSVNURL())) { isSwitched = true; } } if (textStatus != SVNStatusType.STATUS_OBSTRUCTED) { String name = entry.getName(); if (dir != null && dir.hasProperties(name)) { propStatus = SVNStatusType.STATUS_NORMAL; hasProps = true; } isPropsModified = dir != null && dir.hasPropModifications(name); if (hasProps) { isSpecial = !SVNFileUtil.isWindows && dir != null && dir.getProperties(name).getPropertyValue(SVNProperty.SPECIAL) != null; } if (entry.getKind() == SVNNodeKind.FILE && special == isSpecial) { isTextModified = dir != null && dir.hasTextModifications(name, false); } if (isTextModified) { textStatus = SVNStatusType.STATUS_MODIFIED; } if (isPropsModified) { propStatus = SVNStatusType.STATUS_MODIFIED; } if (entry.getPropRejectFile() != null || entry.getConflictOld() != null || entry.getConflictNew() != null || entry.getConflictWorking() != null) { if (dir != null && dir.hasTextConflict(name)) { textStatus = SVNStatusType.STATUS_CONFLICTED; } if (dir != null && dir.hasPropConflict(name)) { propStatus = SVNStatusType.STATUS_CONFLICTED; } } if (entry.isScheduledForAddition() && textStatus != SVNStatusType.STATUS_CONFLICTED) { textStatus = SVNStatusType.STATUS_ADDED; propStatus = SVNStatusType.STATUS_NONE; } else if (entry.isScheduledForReplacement() && textStatus != SVNStatusType.STATUS_CONFLICTED) { textStatus = SVNStatusType.STATUS_REPLACED; propStatus = SVNStatusType.STATUS_NONE; } else if (entry.isScheduledForDeletion() && textStatus != SVNStatusType.STATUS_CONFLICTED) { textStatus = SVNStatusType.STATUS_DELETED; propStatus = SVNStatusType.STATUS_NONE; } if (entry.isIncomplete() && textStatus != SVNStatusType.STATUS_DELETED && textStatus != SVNStatusType.STATUS_ADDED) { textStatus = SVNStatusType.STATUS_INCOMPLETE; } else if (fileKind == SVNNodeKind.NONE) { if (textStatus != SVNStatusType.STATUS_DELETED) { textStatus = SVNStatusType.STATUS_MISSING; } } else if (fileKind != entry.getKind()) { textStatus = SVNStatusType.STATUS_OBSTRUCTED; } else if ((!isSpecial && special) || (isSpecial && !special)) { textStatus = SVNStatusType.STATUS_OBSTRUCTED; } if (fileKind == SVNNodeKind.DIR && entry.getKind() == SVNNodeKind.DIR) { isLocked = wcAccess.isLocked(file); } } if (!reportAll) { if ((textStatus == SVNStatusType.STATUS_NONE || textStatus == SVNStatusType.STATUS_NORMAL) && (propStatus == SVNStatusType.STATUS_NONE || propStatus == SVNStatusType.STATUS_NORMAL) && !isLocked && !isSwitched && entry.getLockToken() == null && repositoryLock == null && entry.getChangelistName() == null && !isFileExternal && treeConflict == null) { return null; } } SVNLock localLock = null; if (entry.getLockToken() != null) { localLock = new SVNLock(null, entry.getLockToken(), entry.getLockOwner(), entry.getLockComment(), SVNDate.parseDate(entry.getLockCreationDate()), null); } File conflictNew = dir != null ? dir.getFile(entry.getConflictNew()) : null; File conflictOld = dir != null ? dir.getFile(entry.getConflictOld()) : null; File conflictWrk = dir != null ? dir.getFile(entry.getConflictWorking()) : null; File conflictProp = dir != null ? dir.getFile(entry.getPropRejectFile()) : null; SVNStatus status = new SVNStatus(entry.getSVNURL(), file, entry.getKind(), SVNRevision.create(entry.getRevision()), SVNRevision.create(entry.getCommittedRevision()), SVNDate.parseDate(entry.getCommittedDate()), entry.getAuthor(), textStatus, propStatus, SVNStatusType.STATUS_NONE, SVNStatusType.STATUS_NONE, isLocked, entry.isCopied(), isSwitched, isFileExternal, conflictNew, conflictOld, conflictWrk, conflictProp, entry.getCopyFromURL(), SVNRevision.create(entry.getCopyFromRevision()), repositoryLock, localLock, entry.asMap(), entry.getChangelistName(), wcFormatNumber, treeConflict); status.setEntry(entry); status.setDepth(entry.isDirectory() ? entry.getDepth() : SVNDepth.UNKNOWN); if (reposRoot == null) { reposRoot = entry.getRepositoryRootURL(); } status.setRepositoryRootURL(reposRoot); if (reposRoot != null && status.getURL() != null && status.getRepositoryRelativePath() == null) { status.setRepositoryRelativePath(SVNURLUtil.getRelativeURL(reposRoot, status.getURL(), false)); } if (textStatus == SVNStatusType.STATUS_CONFLICTED || propStatus == SVNStatusType.STATUS_CONFLICTED || treeConflict != null) { status.setIsConflicted(true); } return status; } public static SVNLock getLock(Map repositoryLocks, SVNURL url, SVNURL reposRoot) { // get decoded path if (reposRoot == null || repositoryLocks == null || repositoryLocks.isEmpty() || url == null) { return null; } String urlString = url.getPath(); String root = reposRoot.getPath(); String path; if (urlString.equals(root)) { path = "/"; } else { path = urlString.substring(root.length()); } return (SVNLock) repositoryLocks.get(path); } }