/* * ==================================================================== * 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 org.tmatesoft.svn.core.*; import org.tmatesoft.svn.core.internal.db.SVNSqlJetDb; import org.tmatesoft.svn.core.internal.db.SVNSqlJetDb.Mode; import org.tmatesoft.svn.core.internal.util.SVNHashMap; import org.tmatesoft.svn.core.internal.wc.SVNFileListUtil; import org.tmatesoft.svn.core.internal.wc.SVNFileType; import org.tmatesoft.svn.core.internal.wc.SVNFileUtil; import org.tmatesoft.svn.core.internal.wc17.SVNWCContext.SVNWCSchedule; import org.tmatesoft.svn.core.internal.wc17.SVNWCContext.ScheduleInternalInfo; import org.tmatesoft.svn.core.internal.wc17.db.*; import org.tmatesoft.svn.core.internal.wc17.db.ISVNWCDb.*; import org.tmatesoft.svn.core.internal.wc17.db.ISVNWCDb.WCDbAdditionInfo.AdditionInfoField; import org.tmatesoft.svn.core.internal.wc17.db.ISVNWCDb.WCDbBaseInfo.BaseInfoField; import org.tmatesoft.svn.core.internal.wc17.db.ISVNWCDb.WCDbInfo.InfoField; import org.tmatesoft.svn.core.internal.wc17.db.ISVNWCDb.WCDbRepositoryInfo.RepositoryInfoField; import org.tmatesoft.svn.core.internal.wc17.db.SVNWCDb.DirParsedInfo; import org.tmatesoft.svn.core.internal.wc17.db.StructureFields.ExternalNodeInfo; import org.tmatesoft.svn.core.internal.wc17.db.StructureFields.InheritedProperties; import org.tmatesoft.svn.core.internal.wc17.db.StructureFields.MovedInfo; import org.tmatesoft.svn.core.internal.wc17.db.StructureFields.NodeOriginInfo; import org.tmatesoft.svn.core.internal.wc2.ng.SvnNgPropertiesManager; import org.tmatesoft.svn.core.wc.ISVNOptions; import org.tmatesoft.svn.core.wc.SVNStatusType; import org.tmatesoft.svn.core.wc2.ISvnObjectReceiver; import org.tmatesoft.svn.core.wc2.SvnStatus; import org.tmatesoft.svn.core.wc2.SvnTarget; import org.tmatesoft.svn.core.wc2.hooks.ISvnFileListHook; import java.io.File; import java.util.*; /** * @version 1.3 * @author TMate Software Ltd. */ public class SVNStatusEditor17 { protected SVNWCContext myWCContext; protected File myPath; protected boolean myIsReportAll; protected boolean myIsNoIgnore; protected SVNDepth myDepth; protected ISvnObjectReceiver<SvnStatus> myStatusHandler; protected Map<File, File> myExternalsMap; protected Collection<String> myGlobalIgnores; protected SVNURL myRepositoryRoot; protected Map<String, SVNLock> myRepositoryLocks; protected long myTargetRevision; protected String myWCRootPath; protected ISvnFileListHook myFileListHook; protected ISvnFileListHook myDefaultFileListHook; protected boolean myIsGetExcluded; private boolean myIgnoreTextMods; public SVNStatusEditor17(File path, SVNWCContext wcContext, ISVNOptions options, boolean noIgnore, boolean reportAll, SVNDepth depth, ISvnObjectReceiver<SvnStatus> handler) { myWCContext = wcContext; myPath = path; myIsNoIgnore = noIgnore; myIsReportAll = reportAll; myDepth = depth; myStatusHandler = handler; myExternalsMap = new HashMap<File, File>(); myGlobalIgnores = getGlobalIgnores(options); myTargetRevision = -1; myDefaultFileListHook = new DefaultSvnFileListHook(); myFileListHook = myDefaultFileListHook; myIsGetExcluded = false; } protected void collectExternals(File path) throws SVNException { myExternalsMap = myWCContext.getDb().getExternalsDefinedBelow(path); } public SVNCommitInfo closeEdit() throws SVNException { final SVNNodeKind localKind = SVNFileType.getNodeKind(SVNFileType.getType(myPath)); final SVNNodeKind kind = myWCContext.readKind(myPath, false); File anchor_abspath; String target_name; boolean skip_root; if (kind == SVNNodeKind.FILE && localKind == SVNNodeKind.FILE) { anchor_abspath = SVNFileUtil.getFileDir(myPath); target_name = SVNFileUtil.getFileName(myPath); skip_root = true; } else if (kind == SVNNodeKind.DIR && localKind == SVNNodeKind.DIR) { anchor_abspath = myPath; target_name = null; skip_root = false; } else { anchor_abspath = SVNFileUtil.getFileDir(myPath); target_name = SVNFileUtil.getFileName(myPath); skip_root = false; } SVNFileType fileType = SVNFileType.getType(anchor_abspath); getDirStatus(anchor_abspath, target_name, skip_root, null, null, fileType, myGlobalIgnores, myDepth, myIsReportAll, true, getDefaultHandler()); return null; } public long getTargetRevision() { return myTargetRevision; } public void targetRevision(long revision) { myTargetRevision = revision; } public void setFileListHook(ISvnFileListHook filesListHook) { if (filesListHook != null) { myFileListHook = filesListHook; } } public SVNDepth getDepth() { return myDepth; } protected ISvnObjectReceiver<SvnStatus> getDefaultHandler() { return myStatusHandler; } protected boolean isReportAll() { return myIsReportAll; } protected boolean isNoIgnore() { return myIsNoIgnore; } public static Collection<String> getGlobalIgnores(ISVNOptions options) { if (options != null) { String[] ignores = options.getIgnorePatterns(); if (ignores != null) { Collection<String> patterns = new HashSet<String>(); for (int i = 0; i < ignores.length; i++) { patterns.add(ignores[i]); } return patterns; } } return Collections.emptySet(); } private static class DefaultSvnFileListHook implements ISvnFileListHook { public Map<String, File> listFiles(File parent) { File[] children = SVNFileListUtil.listFiles(parent); if (children != null) { @SuppressWarnings("unchecked") Map<String, File> map = new SVNHashMap(); for (int i = 0; i < children.length; i++) { map.put(SVNFileUtil.getFileName(children[i]), children[i]); } return map; } return Collections.emptyMap(); } } private void sendStatusStructure(File localAbsPath, WCDbRepositoryInfo parentReposInfo, SVNWCDbInfo info, SVNNodeKind pathKind, boolean pathSpecial, boolean getAll, ISvnObjectReceiver<SvnStatus> handler) throws SVNException { SVNLock repositoryLock = null; if (myRepositoryLocks != null) { WCDbRepositoryInfo reposInfo = getRepositoryRootUrlRelPath(myWCContext, parentReposInfo, info, localAbsPath); if (reposInfo != null && reposInfo.relPath != null) { repositoryLock = (SVNLock) myRepositoryLocks.get("/" + SVNFileUtil.getFilePath(reposInfo.relPath)); } } SvnStatus status = assembleStatus(myWCContext, localAbsPath, parentReposInfo, info, pathKind, pathSpecial, getAll, myIgnoreTextMods, repositoryLock); status = tweakStatus(status); if (status != null && handler != null) { handler.receive(SvnTarget.fromFile(localAbsPath), status); } } private SvnStatus tweakStatus(SvnStatus status) { if (status != null) { if (status.isFileExternal()) { status.setSwitched(false); } } return status; } private void sendUnversionedItem(File nodeAbsPath, SVNNodeKind pathKind, boolean treeConflicted, Collection<String> patterns, boolean noIgnore, int workingCopyFormat, ISvnObjectReceiver<SvnStatus> handler) throws SVNException { boolean isIgnored = SvnNgPropertiesManager.isIgnored(SVNFileUtil.getFileName(nodeAbsPath), patterns); boolean isExternal = isExternal(nodeAbsPath); SvnStatus status = assembleUnversioned17(nodeAbsPath, pathKind, treeConflicted, isIgnored); if (status != null) { if (isExternal) { status.setNodeStatus(SVNStatusType.STATUS_EXTERNAL); } if (status.isConflicted()) { isIgnored = false; } if (workingCopyFormat > 0) { status.setWorkingCopyFormat(workingCopyFormat); } if (handler != null && (noIgnore || !isIgnored || isExternal)) { handler.receive(SvnTarget.fromFile(nodeAbsPath), status); } } } public static SvnStatus assembleUnversioned17(File localAbspath, SVNNodeKind pathKind, boolean treeConflicted, boolean isIgnored) throws SVNException { SvnStatus stat = new SvnStatus(); stat.setPath(localAbspath); stat.setKind(SVNNodeKind.UNKNOWN); stat.setDepth(SVNDepth.UNKNOWN); stat.setNodeStatus(SVNStatusType.STATUS_NONE); stat.setTextStatus(SVNStatusType.STATUS_NONE); stat.setPropertiesStatus(SVNStatusType.STATUS_NONE); stat.setRepositoryNodeStatus(SVNStatusType.STATUS_NONE); stat.setRepositoryTextStatus(SVNStatusType.STATUS_NONE); stat.setRepositoryPropertiesStatus(SVNStatusType.STATUS_NONE); if (pathKind != SVNNodeKind.NONE) { if (isIgnored) { stat.setNodeStatus(SVNStatusType.STATUS_IGNORED); } else { stat.setNodeStatus(SVNStatusType.STATUS_UNVERSIONED); } } else if (treeConflicted) { stat.setNodeStatus(SVNStatusType.STATUS_CONFLICTED); } stat.setRevision(SVNWCContext.INVALID_REVNUM); stat.setChangedRevision(SVNWCContext.INVALID_REVNUM); stat.setRepositoryChangedRevision(SVNWCContext.INVALID_REVNUM); stat.setRepositoryKind(SVNNodeKind.NONE); stat.setConflicted(treeConflicted); stat.setChangelist(null); return stat; } public static SvnStatus assembleStatus(SVNWCContext context, File localAbsPath, WCDbRepositoryInfo parentReposInfo, SVNWCDbInfo info, SVNNodeKind pathKind, boolean pathSpecial, boolean getAll, boolean ignoreTextMods, SVNLock repositoryLock) throws SVNException { boolean switched_p, copied = false; SVNStatusType node_status = SVNStatusType.STATUS_NORMAL; SVNStatusType text_status = SVNStatusType.STATUS_NORMAL; SVNStatusType prop_status = SVNStatusType.STATUS_NONE; if (info == null) { info = readInfo(context, localAbsPath); } if (info.reposRelpath == null || parentReposInfo == null || parentReposInfo.relPath == null) { switched_p = false; } else { String name = SVNFileUtil.getFilePath(SVNWCUtils.skipAncestor(parentReposInfo.relPath, info.reposRelpath)); switched_p = name == null || !name.equals(SVNFileUtil.getFileName(localAbsPath)); } if (info.status == SVNWCDbStatus.Incomplete || info.incomplete) { node_status = SVNStatusType.STATUS_INCOMPLETE; } else if (info.status == SVNWCDbStatus.Deleted) { node_status = SVNStatusType.STATUS_DELETED; if (!info.haveBase || info.haveMoreWork || info.copied) { copied = true; } else if (!info.haveMoreWork && info.haveBase) { copied = false; } else { WCDbDeletionInfo deletionInfo = context.getDb().scanDeletion(localAbsPath); if (deletionInfo.workDelAbsPath != null) { copied = true; } } } else { SVNNodeKind expectedKind = info.kind == SVNWCDbKind.Dir ? SVNNodeKind.DIR : SVNNodeKind.FILE; if (pathKind == null || pathKind != expectedKind) { if (pathKind == null || pathKind == SVNNodeKind.NONE) { node_status = SVNStatusType.STATUS_MISSING; } else { node_status = SVNStatusType.STATUS_OBSTRUCTED; } } } if (info.status != SVNWCDbStatus.Deleted) { if (info.propsMod) { prop_status = SVNStatusType.STATUS_MODIFIED; } else if (info.hadProps) { prop_status = SVNStatusType.STATUS_NORMAL; } } if (info.kind != SVNWCDbKind.Dir && node_status == SVNStatusType.STATUS_NORMAL) { boolean text_modified_p = false; long fileSize = SVNFileUtil.getFileLength(localAbsPath); long fileTime = SVNFileUtil.getFileLastModifiedMicros(localAbsPath); if ((info.kind == SVNWCDbKind.File || info.kind == SVNWCDbKind.Symlink) && (!SVNFileUtil.symlinksSupported() || info.special == pathSpecial)) { if (!info.hasChecksum) { text_modified_p = true; } else if (ignoreTextMods || (pathKind != null && info.recordedSize != -1 && info.recordedModTime != 0 && info.recordedModTime == fileTime && info.recordedSize == fileSize)) { text_modified_p = false; } else { try { text_modified_p = context.isTextModified(localAbsPath, false); } catch (SVNException e) { if (!SVNWCContext.isErrorAccess(e)) { throw e; } text_modified_p = true; } } } else if (SVNFileUtil.symlinksSupported() && (info.special != (pathKind != null && pathSpecial))) { node_status = SVNStatusType.STATUS_OBSTRUCTED; } if (text_modified_p) { text_status = SVNStatusType.STATUS_MODIFIED; } } File movedFromAbsPath = null; boolean conflicted = info.conflicted; if (conflicted) { SVNWCContext.ConflictInfo conflictInfo = context.getConflicted(localAbsPath, true, true, true); if (!conflictInfo.propConflicted && !conflictInfo.textConflicted && !conflictInfo.treeConflicted) { conflicted =false; } } if (node_status == SVNStatusType.STATUS_NORMAL) { if (info.status == SVNWCDbStatus.Added) { copied = info.copied; if (!info.opRoot) { } else if (!info.haveBase && !info.haveMoreWork) { node_status = SVNStatusType.STATUS_ADDED; } else { WCDbInfo infoBelowWorking = context.getDb().readInfoBelowWorking(localAbsPath); if (infoBelowWorking.status != SVNWCDbStatus.NotPresent && infoBelowWorking.status != SVNWCDbStatus.Deleted) { node_status = SVNStatusType.STATUS_REPLACED; } else { node_status = SVNStatusType.STATUS_ADDED; } } if (info.movedHere && info.opRoot) { try { final Structure<MovedInfo> movedInfo = SvnWcDbShared.scanMoved((SVNWCDb) context.getDb(), localAbsPath); movedFromAbsPath = movedInfo.get(MovedInfo.movedFromAbsPath); } catch (SVNException e) { if (e.getErrorMessage().getErrorCode() != SVNErrorCode.WC_PATH_UNEXPECTED_STATUS) { throw e; } } } } } if (node_status == SVNStatusType.STATUS_NORMAL) { node_status = text_status; } if (node_status == SVNStatusType.STATUS_NORMAL && prop_status != SVNStatusType.STATUS_NONE) { node_status = prop_status; } if (!getAll) { if ((node_status == SVNStatusType.STATUS_NONE || node_status == SVNStatusType.STATUS_NORMAL) && !switched_p && !info.locked && (info.lock == null) && repositoryLock == null && info.changelist == null && !conflicted) { return null; } } SVNURL copyFromUrl = null; long copyFromRevision = -1; if (copied) { Structure<NodeOriginInfo> origin = context.getNodeOrigin(localAbsPath, false, NodeOriginInfo.reposRootUrl, NodeOriginInfo.reposRelpath, NodeOriginInfo.revision); copyFromUrl = origin.get(NodeOriginInfo.reposRootUrl); if (copyFromUrl != null) { copyFromUrl = SVNWCUtils.join(copyFromUrl, origin.<File>get(NodeOriginInfo.reposRelpath)); copyFromRevision = origin.lng(NodeOriginInfo.revision); } origin.release(); } SVNNodeKind statusKind = null; switch (info.kind) { case Dir: statusKind = SVNNodeKind.DIR; break; case File: case Symlink: statusKind = SVNNodeKind.FILE; break; case Unknown: default: statusKind = SVNNodeKind.UNKNOWN; } SvnStatus stat = new SvnStatus(); stat.setKind(statusKind); stat.setPath(localAbsPath); WCDbRepositoryInfo reposInfo = getRepositoryRootUrlRelPath(context, parentReposInfo, info, localAbsPath); if (info.lock != null) { stat.setLock(new SVNLock(SVNFileUtil.getFilePath(reposInfo.relPath), info.lock.token, info.lock.owner, info.lock.comment, info.lock.date, null)); } stat.setCopyFromUrl(copyFromUrl); stat.setCopyFromRevision(copyFromRevision); stat.setDepth(info.depth); stat.setNodeStatus(node_status); stat.setTextStatus(text_status); stat.setPropertiesStatus(prop_status); stat.setRepositoryNodeStatus(SVNStatusType.STATUS_NONE); stat.setRepositoryTextStatus(SVNStatusType.STATUS_NONE); stat.setRepositoryPropertiesStatus(SVNStatusType.STATUS_NONE); stat.setSwitched(switched_p); stat.setCopied(copied); stat.setRepositoryLock(repositoryLock); stat.setRevision(info.revnum); stat.setChangedRevision(info.changedRev); stat.setChangedAuthor(info.changedAuthor); stat.setChangedDate(info.changedDate); stat.setRepositoryKind(SVNNodeKind.NONE); stat.setRepositoryChangedRevision(SVNWCContext.INVALID_REVNUM); stat.setRepositoryChangedDate(null); stat.setRepositoryChangedAuthor(null); stat.setWcLocked(info.locked); stat.setConflicted(conflicted); stat.setVersioned(true); stat.setChangelist(info.changelist); stat.setRepositoryRootUrl(reposInfo.rootUrl); stat.setRepositoryRelativePath(SVNFileUtil.getFilePath(reposInfo.relPath)); stat.setRepositoryUuid(reposInfo.uuid); stat.setTextStatus(text_status); stat.setNodeStatus(node_status); stat.setPropertiesStatus(prop_status); if (stat.isVersioned() && stat.isConflicted()) { SVNWCContext.ConflictInfo conflictInfo = context.getConflicted(stat.getPath(), true, true, true); if (conflictInfo.textConflicted) { stat.setTextStatus(SVNStatusType.STATUS_CONFLICTED); } if (conflictInfo.propConflicted) { stat.setPropertiesStatus(SVNStatusType.STATUS_CONFLICTED); } if (conflictInfo.textConflicted || conflictInfo.propConflicted) { stat.setNodeStatus(SVNStatusType.STATUS_CONFLICTED); } } stat.setFileExternal(info.fileExternal); // // if (stat.isSwitched() && stat.isVersioned() && stat.getKind() == SVNNodeKind.FILE) { // try { // Structure<ExternalNodeInfo> externalInfo = SvnWcDbExternals.readExternal(context, stat.getPath(), stat.getPath(), ExternalNodeInfo.kind); // if (externalInfo != null) { // stat.setFileExternal(externalInfo.<SVNWCDbKind>get(ExternalNodeInfo.kind) == SVNWCDbKind.File); // stat.setSwitched(false); // stat.setNodeStatus(stat.getTextStatus()); // // externalInfo.release(); // } // } catch (SVNException e) { // if (e.getErrorMessage().getErrorCode() != SVNErrorCode.WC_PATH_NOT_FOUND) { // throw e; // } // } // // } // stat.setMovedFromPath(movedFromAbsPath); if (info.movedToAbsPath != null) { stat.setMovedToPath(info.movedToAbsPath); } if (info.format != -1) { stat.setWorkingCopyFormat(info.format); } return stat; } private boolean isExternal(File nodeAbsPath) { if (!myExternalsMap.containsKey(nodeAbsPath)) { for (Iterator<File> paths = myExternalsMap.keySet().iterator(); paths.hasNext();) { File externalPath = (File) paths.next(); if (SVNWCUtils.isChild(nodeAbsPath, externalPath)) { return true; } } return false; } return true; } private Collection<String> collectIgnorePatterns(SVNWCDbRoot root, File localRelPath, Collection<String> ignores) throws SVNException { final List<String> patterns = new ArrayList<String>(); if (ignores != null) { patterns.addAll(ignores); } final SVNProperties props = SvnWcDbProperties.readProperties(root, localRelPath); if (props != null) { final String localIgnores = props.getStringValue(SVNProperty.IGNORE); if (localIgnores != null) { SvnNgPropertiesManager.splitAndAppend(patterns, localIgnores); } final String inheritedIgnores = props.getStringValue(SVNProperty.INHERITABLE_IGNORES); if (inheritedIgnores != null) { SvnNgPropertiesManager.splitAndAppend(patterns, inheritedIgnores); } } List<Structure<InheritedProperties>> inheritedProps = null; try { inheritedProps = SvnWcDbProperties.readInheritedProperties(root, localRelPath, SVNProperty.INHERITABLE_IGNORES); } catch (SVNException e) { if (e.getErrorMessage().getErrorCode() == SVNErrorCode.WC_PATH_UNEXPECTED_STATUS) { return patterns; } else { throw e; } } for (Structure<InheritedProperties> element : inheritedProps) { final SVNProperties inherited = element.get(InheritedProperties.properties); SvnNgPropertiesManager.splitAndAppend(patterns, inherited.getStringValue(SVNProperty.INHERITABLE_IGNORES)); } return patterns; } public void setRepositoryInfo(SVNURL repositoryRoot, HashMap<String, SVNLock> repositoryLocks) { myRepositoryRoot = repositoryRoot; myRepositoryLocks = repositoryLocks; } private static SVNWCDbInfo readInfo(SVNWCContext context, File localAbsPath) throws SVNException { SVNWCDbInfo result = new SVNWCDbInfo(); WCDbInfo readInfo = context.getDb().readInfo(localAbsPath, InfoField.status, InfoField.kind, InfoField.revision, InfoField.reposRelPath, InfoField.reposRootUrl, InfoField.reposUuid, InfoField.changedRev, InfoField.changedDate, InfoField.changedAuthor, InfoField.depth, InfoField.checksum, InfoField.lock, InfoField.translatedSize, InfoField.lastModTime, InfoField.changelist, InfoField.originalReposRelpath, InfoField.conflicted, InfoField.opRoot, InfoField.hadProps, InfoField.propsMod, InfoField.haveBase, InfoField.haveMoreWork, InfoField.movedHere, InfoField.movedTo); result.load(readInfo); result.locked = context.getDb().isWCLocked(localAbsPath); WCDbBaseInfo baseInfo = null; if (result.haveBase && (result.status == SVNWCDbStatus.Added || result.status == SVNWCDbStatus.Deleted)) { baseInfo = context.getDb().getBaseInfo(localAbsPath, BaseInfoField.lock, BaseInfoField.updateRoot); result.lock = baseInfo.lock; } if (result.haveBase && result.kind == SVNWCDbKind.File) { if (baseInfo == null) { baseInfo = context.getDb().getBaseInfo(localAbsPath, BaseInfoField.lock, BaseInfoField.updateRoot); } result.fileExternal = baseInfo.updateRoot; } else { result.fileExternal = false; } result.hasChecksum = readInfo.checksum != null; result.copied = readInfo.originalReposRelpath != null; if (result.kind == SVNWCDbKind.File && (result.hadProps || result.propsMod)) { SVNProperties properties; if (result.propsMod) { properties = context.getDb().readProperties(localAbsPath); } else { properties = context.getDb().readPristineProperties(localAbsPath); } result.special = properties.getSVNPropertyValue(SVNProperty.SPECIAL) != null; } DirParsedInfo parsed = ((SVNWCDb) context.getDb()).parseDir(localAbsPath, Mode.ReadOnly); result.format = parsed.wcDbDir.getWCRoot().getFormat(); return result; } public void walkStatus(File localAbsPath, SVNDepth depth, boolean getAll, boolean noIgnore, boolean ignoreTextMods, Collection<String> ignorePatterns) throws SVNException { collectExternals(localAbsPath); if (ignorePatterns == null) { ignorePatterns = getGlobalIgnores(myWCContext.getOptions()); } SVNWCDbInfo dirInfo = null; try { dirInfo = readInfo(myWCContext, localAbsPath); } catch (SVNException e) { if (e.getErrorMessage().getErrorCode() != SVNErrorCode.WC_PATH_NOT_FOUND) { throw e; } } SVNFileType fileType = SVNFileType.getType(localAbsPath); File anchorAbsPath; String targetName; boolean skipRoot; if (dirInfo != null && dirInfo.kind == SVNWCDbKind.Dir && dirInfo.status != SVNWCDbStatus.Excluded && dirInfo.status != SVNWCDbStatus.NotPresent && dirInfo.status != SVNWCDbStatus.ServerExcluded) { anchorAbsPath = localAbsPath; targetName = null; skipRoot = false; } else { dirInfo = null; anchorAbsPath = SVNFileUtil.getParentFile(localAbsPath); targetName = SVNFileUtil.getFileName(localAbsPath); skipRoot = true; } myIgnoreTextMods = ignoreTextMods; getDirStatus(anchorAbsPath, targetName, skipRoot, null, dirInfo, fileType, ignorePatterns, depth, getAll, noIgnore, getDefaultHandler()); } private SVNWCDbRoot wcRoot; protected void getDirStatus(File localAbsPath, String selected, boolean skipThisDir, WCDbRepositoryInfo parentReposInfo, SVNWCDbInfo dirInfo, SVNFileType fileType, Collection<String> ignorePatterns, SVNDepth depth, boolean getAll, boolean noIgnore, ISvnObjectReceiver<SvnStatus> handler) throws SVNException { myWCContext.checkCancelled(); if (depth == SVNDepth.UNKNOWN) { depth = SVNDepth.INFINITY; } Map<String, File> childrenFiles = myFileListHook.listFiles(localAbsPath); if (childrenFiles == null) { childrenFiles = Collections.emptyMap(); } final Set<String> allChildren = new HashSet<String>(); final Set<String> conflicts = new HashSet<String>(); final Map<String, SVNWCDbInfo> nodes = new HashMap<String, ISVNWCDb.SVNWCDbInfo>(); Collection<String> patterns = null; if (dirInfo == null) { dirInfo = readInfo(myWCContext, localAbsPath); } WCDbRepositoryInfo dirReposInfo = getRepositoryRootUrlRelPath(myWCContext, parentReposInfo, dirInfo, localAbsPath); if (wcRoot == null) { DirParsedInfo pdh = ((SVNWCDb) myWCContext.getDb()).parseDir(localAbsPath, Mode.ReadOnly); wcRoot = pdh.wcDbDir.getWCRoot(); } if (selected == null) { File localRelPath = wcRoot.computeRelPath(localAbsPath); ((SVNWCDb) myWCContext.getDb()).readChildren(wcRoot, localRelPath, nodes, conflicts); allChildren.addAll(nodes.keySet()); allChildren.addAll(childrenFiles.keySet()); allChildren.addAll(conflicts); } else { File selectedAbsPath = SVNFileUtil.createFilePath(localAbsPath, selected); SVNWCDbInfo info = null; try { info = readInfo(myWCContext, selectedAbsPath); } catch (SVNException e) { if (e.getErrorMessage().getErrorCode() != SVNErrorCode.WC_PATH_NOT_FOUND) { throw e; } } if (info != null) { if (!info.conflicted || info.status != SVNWCDbStatus.Normal || info.kind != SVNWCDbKind.Unknown) { nodes.put(selected, info); } if (info.conflicted) { conflicts.add(selected); } } allChildren.add(selected); } if (selected == null) { if (!skipThisDir) { sendStatusStructure(localAbsPath, parentReposInfo, dirInfo, SVNFileType.getNodeKind(fileType), fileType == SVNFileType.SYMLINK, getAll, handler); } if (depth == SVNDepth.EMPTY) { return; } } for(String name : allChildren) { File nodeAbsPath = SVNFileUtil.createFilePath(localAbsPath, name); SVNFileType nodeFileType = childrenFiles.containsKey(name) ? SVNFileType.getType(childrenFiles.get(name)) : null; SVNWCDbInfo nodeInfo = nodes.get(name); if (nodeInfo != null) { if (nodeInfo.status != SVNWCDbStatus.NotPresent && nodeInfo.status != SVNWCDbStatus.Excluded && nodeInfo.status != SVNWCDbStatus.ServerExcluded) { if (depth == SVNDepth.FILES && nodeInfo.kind == SVNWCDbKind.Dir) { continue; } sendStatusStructure(nodeAbsPath, dirReposInfo, nodeInfo, SVNFileType.getNodeKind(nodeFileType), nodeFileType == SVNFileType.SYMLINK, getAll, handler); if (depth == SVNDepth.INFINITY && nodeInfo.kind == SVNWCDbKind.Dir) { getDirStatus(nodeAbsPath, null, true, dirReposInfo, nodeInfo, nodeFileType, ignorePatterns, SVNDepth.INFINITY, getAll, noIgnore, handler); } continue; } } if (conflicts.contains(name)) { if (ignorePatterns != null && patterns == null) { patterns = collectIgnorePatterns(wcRoot, wcRoot.computeRelPath(localAbsPath), ignorePatterns); } sendUnversionedItem(nodeAbsPath, SVNFileType.getNodeKind(nodeFileType), true, patterns, noIgnore, wcRoot.getFormat(), handler); continue; } if (nodeFileType == null) { continue; } if (depth == SVNDepth.FILES && nodeFileType == SVNFileType.DIRECTORY) { continue; } if (SVNFileUtil.getAdminDirectoryName().equals(name)) { continue; } if (ignorePatterns != null && patterns == null) { patterns = collectIgnorePatterns(wcRoot, wcRoot.computeRelPath(localAbsPath), ignorePatterns); } sendUnversionedItem(nodeAbsPath, SVNFileType.getNodeKind(nodeFileType), false, patterns, noIgnore || selected != null, wcRoot.getFormat(), handler); } } private static WCDbRepositoryInfo getRepositoryRootUrlRelPath(SVNWCContext context, WCDbRepositoryInfo parentRelPath, SVNWCDbInfo info, File localAbsPath) throws SVNException { WCDbRepositoryInfo result = new WCDbRepositoryInfo(); if (info.reposRelpath != null && info.reposRootUrl != null) { result.relPath = info.reposRelpath; result.uuid = info.reposUuid; result.rootUrl = info.reposRootUrl; } else if (parentRelPath != null && parentRelPath.rootUrl != null && parentRelPath.relPath != null) { result.relPath = SVNFileUtil.createFilePath(parentRelPath.relPath, SVNFileUtil.getFileName(localAbsPath)); result.uuid = parentRelPath.uuid; result.rootUrl = parentRelPath.rootUrl; } else if (info.status == SVNWCDbStatus.Added) { WCDbAdditionInfo additionInfo = context.getDb().scanAddition(localAbsPath, AdditionInfoField.reposRelPath, AdditionInfoField.reposRootUrl, AdditionInfoField.reposUuid); result.relPath = additionInfo.reposRelPath; result.uuid = additionInfo.reposUuid; result.rootUrl = additionInfo.reposRootUrl; } else if (info.haveBase) { WCDbRepositoryInfo repoInfo = context.getDb().scanBaseRepository(localAbsPath, RepositoryInfoField.relPath, RepositoryInfoField.rootUrl, RepositoryInfoField.uuid); result.relPath = repoInfo.relPath; result.uuid = repoInfo.uuid; result.rootUrl = repoInfo.rootUrl; } return result; } public static SvnStatus internalStatus(SVNWCContext context, File localAbsPath) throws SVNException { SVNWCDbKind node_kind; SVNWCDbStatus node_status = null; boolean conflicted; assert (SVNWCDb.isAbsolute(localAbsPath)); SVNNodeKind kind = SVNFileType.getNodeKind(SVNFileType.getType(localAbsPath)); try { WCDbInfo info = context.getDb().readInfo(localAbsPath, InfoField.status, InfoField.kind, InfoField.conflicted); node_status = info.status; node_kind = info.kind; conflicted = info.conflicted; } catch (SVNException e) { if (e.getErrorMessage().getErrorCode() != SVNErrorCode.WC_PATH_NOT_FOUND) { throw e; } node_kind = SVNWCDbKind.Unknown; conflicted = false; } if (node_status == SVNWCDbStatus.ServerExcluded || node_status == SVNWCDbStatus.NotPresent || node_status == SVNWCDbStatus.Excluded) { node_kind = SVNWCDbKind.Unknown; } if (node_kind != SVNWCDbKind.Unknown) { /* Check for hidden in the parent stub */ boolean hidden = context.getDb().isNodeHidden(localAbsPath); if (hidden) { node_kind = SVNWCDbKind.Unknown; } } if (node_kind == SVNWCDbKind.Unknown) { return assembleUnversioned17(localAbsPath, kind, conflicted, false); } boolean isRoot; if (SVNFileUtil.getParentFile(localAbsPath) == null) { isRoot = true; } else { isRoot = context.getDb().isWCRoot(localAbsPath); } WCDbRepositoryInfo reposInfo = new WCDbRepositoryInfo(); if (SVNFileUtil.getFileDir(localAbsPath) != null && !isRoot) { File parent_abspath = SVNFileUtil.getFileDir(localAbsPath); try { WCDbInfo parent_info = context.getDb().readInfo(parent_abspath, InfoField.reposRelPath, InfoField.reposRootUrl, InfoField.reposUuid); reposInfo.relPath = parent_info.reposRelPath; reposInfo.rootUrl = parent_info.reposRootUrl; reposInfo.uuid = parent_info.reposUuid; } catch (SVNException e) { if (e.getErrorMessage().getErrorCode() == SVNErrorCode.WC_PATH_NOT_FOUND || e.getErrorMessage().getErrorCode() == SVNErrorCode.WC_NOT_WORKING_COPY) /* || SVN_WC__ERR_IS_NOT_CURRENT_WC(err)) */ { reposInfo.relPath = null; reposInfo.rootUrl = null; reposInfo.uuid = null; } else { throw e; } } } return assembleStatus(context, localAbsPath, reposInfo, null, kind, false, true, false, null); } }