/*
* ====================================================================
* 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.util.SVNDate;
import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil;
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
import org.tmatesoft.svn.core.internal.wc.SVNFileUtil;
import org.tmatesoft.svn.core.internal.wc17.db.ISVNWCDb.SVNWCDbKind;
import org.tmatesoft.svn.core.internal.wc17.db.ISVNWCDb.WCDbRepositoryInfo;
import org.tmatesoft.svn.core.internal.wc17.db.SVNWCDb;
import org.tmatesoft.svn.core.io.ISVNEditor;
import org.tmatesoft.svn.core.io.diff.SVNDiffWindow;
import org.tmatesoft.svn.core.wc.ISVNOptions;
import org.tmatesoft.svn.core.wc.SVNRevision;
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 java.io.File;
import java.io.OutputStream;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
/**
* @version 1.3
* @author TMate Software Ltd.
*/
public class SVNRemoteStatusEditor17 extends SVNStatusEditor17 implements ISVNEditor, ISvnObjectReceiver<SvnStatus> {
private boolean myIsRootOpen;
private SvnStatus myAnchorStatus;
private DirectoryInfo myDirectoryInfo;
private FileInfo myFileInfo;
private File myAnchorAbsPath;
private String myTargetBaseName;
private File myTargetAbsPath;
private boolean myIsMarkingDeleted;
public SVNRemoteStatusEditor17(File anchorAbsPath, String targetBaseName, SVNWCContext wcContext, ISVNOptions options, boolean includeIgnored, boolean reportAll, SVNDepth depth,
ISvnObjectReceiver<SvnStatus> realHandler) throws SVNException {
super(SVNFileUtil.createFilePath(anchorAbsPath, targetBaseName), wcContext, options, includeIgnored, reportAll, depth, realHandler);
myAnchorStatus = internalStatus(wcContext, anchorAbsPath);
myAnchorAbsPath = anchorAbsPath;
myTargetBaseName = targetBaseName;
myTargetAbsPath = SVNFileUtil.createFilePath(anchorAbsPath, targetBaseName);
collectExternals(myTargetAbsPath);
}
public void openRoot(long revision) throws SVNException {
myIsRootOpen = true;
myDirectoryInfo = new DirectoryInfo(null, null);
}
public void deleteEntry(String path, long revision) throws SVNException {
final File local_abspath = SVNFileUtil.createFilePath(myAnchorAbsPath, path);
tweakStatusHash(myDirectoryInfo, new DirectoryInfo(path, myDirectoryInfo), local_abspath, SVNStatusType.STATUS_DELETED, SVNStatusType.STATUS_NONE, SVNStatusType.STATUS_NONE,
SVNRevision.create(revision), null);
if (myDirectoryInfo.parent != null && myTargetBaseName == null)
tweakStatusHash(myDirectoryInfo.parent, myDirectoryInfo, myDirectoryInfo.localAbsPath, SVNStatusType.STATUS_MODIFIED, SVNStatusType.STATUS_MODIFIED,
SVNStatusType.STATUS_NONE, null, null);
}
private void tweakStatusHash(DirectoryInfo dirInfo, DirectoryInfo childDir, File localAbsPath, SVNStatusType reposNodeStatus, SVNStatusType reposTextStatus,
SVNStatusType reposPropStatus, SVNRevision deletedRev, SVNLock reposLock) throws SVNException {
Map<File, SvnStatus> statushash = dirInfo.statii;
/* Is PATH already a hash-key? */
SvnStatus statstruct = statushash.get(localAbsPath);
/* If not, make it so. */
if (statstruct == null) {
/*
* If this item isn't being added, then we're most likely dealing
* with a non-recursive (or at least partially non-recursive)
* working copy. Due to bugs in how the client reports the state of
* non-recursive working copies, the repository can send back
* responses about paths that don't even exist locally. Our best
* course here is just to ignore those responses. After all, if the
* client had reported correctly in the first, that path would
* either be mentioned as an 'add' or not mentioned at all,
* depending on how we eventually fix the bugs in non-recursivity.
* See issue #2122 for details.
*/
if (reposNodeStatus != SVNStatusType.STATUS_ADDED)
return;
/* Use the public API to get a statstruct, and put it into the hash. */
statstruct = internalStatus(myWCContext, localAbsPath);
if (statstruct.getNodeStatus() == SVNStatusType.STATUS_UNVERSIONED || statstruct.getNodeStatus() == SVNStatusType.STATUS_NONE) {
statstruct.setWorkingCopyFormat(myAnchorStatus.getWorkingCopyFormat());
}
statstruct.setRepositoryLock(reposLock);
statushash.put(localAbsPath, statstruct);
}
/* Merge a repos "delete" + "add" into a single "replace". */
if ((reposNodeStatus == SVNStatusType.STATUS_ADDED) && (statstruct.getRepositoryNodeStatus() == SVNStatusType.STATUS_DELETED))
reposNodeStatus = SVNStatusType.STATUS_REPLACED;
/* Tweak the structure's repos fields. */
if (reposNodeStatus != null)
statstruct.setRepositoryNodeStatus(reposNodeStatus);
if (reposTextStatus != null)
statstruct.setRepositoryTextStatus(reposTextStatus);
if (reposPropStatus != null)
statstruct.setRepositoryPropertiesStatus(reposPropStatus);
/* Copy out-of-date info. */
statstruct.setRepositoryRootUrl(myRepositoryRoot);
statstruct.setRepositoryRelativePath(childDir.computeRepositoryRelativePath());
/*
* The last committed date, and author for deleted items isn't
* available.
*/
if (statstruct.getRepositoryNodeStatus() == SVNStatusType.STATUS_DELETED) {
statstruct.setRepositoryKind(statstruct.getKind());
/*
* Pre 1.5 servers don't provide the revision a path was deleted. So
* we punt and use the last committed revision of the path's parent,
* which has some chance of being correct. At worse it is a higher
* revision than the path was deleted, but this is better than
* nothing...
*/
if (deletedRev == null || !deletedRev.isValid())
statstruct.setRepositoryChangedRevision(dirInfo.ood_changed_rev);
else
statstruct.setRepositoryChangedRevision(deletedRev.getNumber());
} else {
statstruct.setRepositoryKind(childDir.ood_kind);
statstruct.setRepositoryChangedRevision(childDir.ood_changed_rev);
statstruct.setRepositoryChangedDate(childDir.ood_changed_date);
if (childDir.ood_changed_author != null)
statstruct.setRepositoryChangedAuthor(childDir.ood_changed_author);
}
return;
}
public void addDir(String path, String copyFromPath, long copyFromRevision) throws SVNException {
myDirectoryInfo = new DirectoryInfo(path, myDirectoryInfo);
myDirectoryInfo.added = true;
myDirectoryInfo.parent.text_changed = true;
}
public void openDir(String path, long revision) throws SVNException {
myDirectoryInfo = new DirectoryInfo(path, myDirectoryInfo);
}
public void changeDirProperty(String name, SVNPropertyValue value) throws SVNException {
if (!name.startsWith(SVNProperty.SVN_ENTRY_PREFIX) && !name.startsWith(SVNProperty.SVN_WC_PREFIX)) {
myDirectoryInfo.prop_changed = true;
}
/* Note any changes to the repository. */
if (value != null) {
if (SVNProperty.COMMITTED_REVISION.equals(name)) {
try {
myDirectoryInfo.ood_changed_rev = Long.parseLong(value.getString());
} catch (NumberFormatException nfe) {
myDirectoryInfo.ood_changed_rev = SVNWCDb.INVALID_REVNUM;
}
} else if (SVNProperty.LAST_AUTHOR.equals(name)) {
myDirectoryInfo.ood_changed_author = value.getString();
} else if (SVNProperty.COMMITTED_DATE.equals(name)) {
myDirectoryInfo.ood_changed_date = SVNDate.parseDate(value.getString());
}
}
}
public void closeDir() throws SVNException {
DirectoryInfo db = myDirectoryInfo;
DirectoryInfo pb = db.parent;
/*
* If nothing has changed and directory has no out of date descendants,
* return.
*/
if (db.added || db.prop_changed || db.text_changed || db.ood_changed_rev != SVNWCDb.INVALID_REVNUM) {
SVNStatusType repos_node_status;
SVNStatusType repos_text_status;
SVNStatusType repos_prop_status;
/* If this is a new directory, add it to the statushash. */
if (db.added) {
repos_node_status = SVNStatusType.STATUS_ADDED;
repos_text_status = SVNStatusType.STATUS_ADDED;
repos_prop_status = db.prop_changed ? SVNStatusType.STATUS_ADDED : SVNStatusType.STATUS_NONE;
} else {
repos_node_status = (db.text_changed || db.prop_changed) ? SVNStatusType.STATUS_MODIFIED : SVNStatusType.STATUS_NONE;
repos_text_status = db.text_changed ? SVNStatusType.STATUS_MODIFIED : SVNStatusType.STATUS_NONE;
repos_prop_status = db.prop_changed ? SVNStatusType.STATUS_MODIFIED : SVNStatusType.STATUS_NONE;
}
/*
* Maybe add this directory to its parent's status hash. Note that
* tweak_statushash won't do anything if repos_text_status is not
* svn_wc_status_added.
*/
if (pb != null) {
/*
* ### When we add directory locking, we need to find a ###
* directory lock here.
*/
tweakStatusHash(pb, db, db.localAbsPath, repos_node_status, repos_text_status, repos_prop_status, null, null);
} else {
/*
* We're editing the root dir of the WC. As its repos status
* info isn't otherwise set, set it directly to trigger
* invocation of the status callback below.
*/
myAnchorStatus.setRepositoryNodeStatus(repos_node_status);
myAnchorStatus.setRepositoryPropertiesStatus(repos_prop_status);
myAnchorStatus.setRepositoryTextStatus(repos_text_status);
/* If the root dir is out of date set the ood info directly too. */
if (db.ood_changed_rev != myAnchorStatus.getRevision()) {
myAnchorStatus.setRepositoryChangedRevision(db.ood_changed_rev);
myAnchorStatus.setRepositoryChangedDate(db.ood_changed_date);
myAnchorStatus.setRepositoryKind(db.ood_kind);
myAnchorStatus.setRepositoryChangedAuthor(db.ood_changed_author);
}
}
}
/*
* Handle this directory's statuses, and then note in the parent that
* this has been done.
*/
if (pb != null && !db.excluded) {
boolean was_deleted = false;
SvnStatus dir_status = pb.statii.get(db.localAbsPath);
/* See if the directory was deleted or replaced. */
if (dir_status != null && ((dir_status.getRepositoryNodeStatus() == SVNStatusType.STATUS_DELETED) || (dir_status.getRepositoryNodeStatus() == SVNStatusType.STATUS_REPLACED)))
was_deleted = true;
/* Now do the status reporting. */
WCDbRepositoryInfo dirReposInfo = new WCDbRepositoryInfo();
if (dirReposInfo != null) {
dirReposInfo.rootUrl = dir_status.getRepositoryRootUrl();
dirReposInfo.relPath = SVNFileUtil.createFilePath(dir_status.getRepositoryRelativePath());
dirReposInfo.uuid = dir_status.getRepositoryUuid();
}
handleStatii(dirReposInfo, db.statii, was_deleted, db.depth);
if (dir_status != null && isSendableStatus(dir_status))
getDefaultHandler().receive(SvnTarget.fromFile(dir_status.getPath()), dir_status);
pb.statii.remove(db.localAbsPath);
} else if (pb == null) {
/*
* If this is the top-most directory, and the operation had a
* target, we should only report the target.
*/
if (myTargetBaseName != null && !"".equals(myTargetBaseName)) {
SvnStatus tgt_status = db.statii.get(myTargetAbsPath);
if (tgt_status != null) {
if (tgt_status.isVersioned() && tgt_status.getKind() == SVNNodeKind.DIR) {
getDirStatus(myTargetAbsPath, null, true, null, null, null, null, getDepth(), isReportAll(), isNoIgnore(), getDefaultHandler());
}
if (isSendableStatus(tgt_status)) {
getDefaultHandler().receive(SvnTarget.fromFile(tgt_status.getPath()), tgt_status);
}
}
} else {
/*
* Otherwise, we report on all our children and ourself. Note
* that our directory couldn't have been deleted, because it is
* the root of the edit drive.
*/
WCDbRepositoryInfo dirReposInfo = new WCDbRepositoryInfo();
if (dirReposInfo != null) {
dirReposInfo.rootUrl = myAnchorStatus.getRepositoryRootUrl();
dirReposInfo.relPath = SVNFileUtil.createFilePath(myAnchorStatus.getRepositoryRelativePath());
dirReposInfo.uuid = myAnchorStatus.getRepositoryUuid();
}
handleStatii(dirReposInfo, db.statii, false, getDepth());
if (isSendableStatus(myAnchorStatus)) {
getDefaultHandler().receive(SvnTarget.fromFile(myAnchorStatus.getPath()), myAnchorStatus);
}
myAnchorStatus = null;
}
}
myDirectoryInfo = myDirectoryInfo.parent;
}
private boolean isSendableStatus(SvnStatus status) {
/* If the repository status was touched at all, it's interesting. */
if (status.getRepositoryNodeStatus() != SVNStatusType.STATUS_NONE)
return true;
/* If there is a lock in the repository, send it. */
if (status.getRepositoryLock() != null)
return true;
/* If the item is ignored, and we don't want ignores, skip it. */
if ((status.getNodeStatus() == SVNStatusType.STATUS_IGNORED) && (!isNoIgnore()))
return false;
/*
* If we want everything, we obviously want this single-item subset of
* everything.
*/
if (isReportAll())
return true;
/* If the item is unversioned, display it. */
if (status.getNodeStatus() == SVNStatusType.STATUS_UNVERSIONED)
return true;
/* If the text, property or tree state is interesting, send it. */
if ((status.getNodeStatus() != SVNStatusType.STATUS_NONE && (status.getNodeStatus() != SVNStatusType.STATUS_NORMAL)))
return true;
if (status.isConflicted())
return true;
/* If it's switched, send it. */
if (status.isSwitched())
return true;
/* If there is a lock token, send it. */
if (status.isVersioned() && status.getLock() != null)
return true;
/* If the entry is associated with a changelist, send it. */
if (status.getChangelist() != null)
return true;
/* Otherwise, don't send it. */
return false;
}
private void handleStatii(WCDbRepositoryInfo reposInfo, Map<File, SvnStatus> statii, boolean dirWasDeleted, SVNDepth depth) throws SVNException {
ISvnObjectReceiver<SvnStatus> handler = dirWasDeleted ? this : getDefaultHandler();
for (Iterator<File> paths = statii.keySet().iterator(); paths.hasNext();) {
File localAbsPath = paths.next();
SvnStatus status = statii.get(localAbsPath);
if (status.getKind() == SVNNodeKind.DIR && (depth == SVNDepth.UNKNOWN || depth == SVNDepth.INFINITY)) {
getDirStatus(localAbsPath, null, true, reposInfo, null, null, myGlobalIgnores, depth, isReportAll(), isNoIgnore(), handler);
}
if (dirWasDeleted) {
status.setRepositoryNodeStatus(SVNStatusType.STATUS_DELETED);
}
if (isSendableStatus(status)) {
getDefaultHandler().receive(SvnTarget.fromFile(localAbsPath), status);
}
}
}
public void addFile(String path, String copyFromPath, long copyFromRevision) throws SVNException {
myFileInfo = new FileInfo(myDirectoryInfo, path, true);
myFileInfo.added = true;
myDirectoryInfo.text_changed = true;
}
public void openFile(String path, long revision) throws SVNException {
myFileInfo = new FileInfo(myDirectoryInfo, path, false);
}
public void applyTextDelta(String path, String baseChecksum) throws SVNException {
myFileInfo.text_changed = true;
myFileInfo.baseChecksum = baseChecksum;
}
public void changeFileProperty(String path, String propertyName, SVNPropertyValue propertyValue) throws SVNException {
if (!propertyName.startsWith(SVNProperty.SVN_ENTRY_PREFIX) && !propertyName.startsWith(SVNProperty.SVN_WC_PREFIX)) {
myFileInfo.prop_changed = true;
}
if (propertyValue != null) {
if (SVNProperty.COMMITTED_REVISION.equals(propertyName)) {
try {
myFileInfo.ood_changed_rev = Long.parseLong(propertyValue.getString());
} catch (NumberFormatException nfe) {
myFileInfo.ood_changed_rev = SVNWCDb.INVALID_REVNUM;
}
} else if (SVNProperty.COMMITTED_DATE.equals(propertyName)) {
myFileInfo.ood_changed_date = SVNDate.parseDate(propertyValue.getString());
} else if (SVNProperty.LAST_AUTHOR.equals(propertyName)) {
myFileInfo.ood_changed_author = propertyValue.getString();
}
}
}
public void closeFile(String path, String textChecksum) throws SVNException {
SVNStatusType repos_node_status;
SVNStatusType repos_text_status;
SVNStatusType repos_prop_status;
SVNLock repos_lock = null;
if (myFileInfo.baseChecksum != null && textChecksum != null) {
myFileInfo.text_changed = !myFileInfo.baseChecksum.equals(textChecksum);
}
/* If nothing has changed, return. */
if (!(myFileInfo.added || myFileInfo.prop_changed || myFileInfo.text_changed))
return;
/* If this is a new file, add it to the statushash. */
if (myFileInfo.added) {
repos_node_status = SVNStatusType.STATUS_ADDED;
repos_text_status = SVNStatusType.STATUS_ADDED;
repos_prop_status = myFileInfo.prop_changed ? SVNStatusType.STATUS_ADDED : SVNStatusType.STATUS_NONE;
if (myRepositoryLocks != null) {
File dir_repos_relpath = findDirReposRelpath(myFileInfo.parent);
if (dir_repos_relpath != null) {
/*
* repos_lock still uses the deprecated filesystem absolute
* path format
*/
File repos_relpath = SVNFileUtil.createFilePath(dir_repos_relpath, myFileInfo.name);
String reposRelPathWithDirectSlashes = repos_relpath.toString().replace(File.separatorChar, '/');
repos_lock = (SVNLock) myRepositoryLocks.get(SVNEncodingUtil.uriDecode("/" + reposRelPathWithDirectSlashes));
}
}
} else {
repos_node_status = (myFileInfo.text_changed || myFileInfo.prop_changed) ? SVNStatusType.STATUS_MODIFIED : SVNStatusType.STATUS_NONE;
repos_text_status = myFileInfo.text_changed ? SVNStatusType.STATUS_MODIFIED : SVNStatusType.STATUS_NONE;
repos_prop_status = myFileInfo.prop_changed ? SVNStatusType.STATUS_MODIFIED : SVNStatusType.STATUS_NONE;
}
tweakStatusHash(myFileInfo, myFileInfo.localAbsPath, repos_node_status, repos_text_status, repos_prop_status, SVNWCDb.INVALID_REVNUM, repos_lock);
}
private void tweakStatusHash(FileInfo fileInfo, File localAbsPath, SVNStatusType reposNodeStatus, SVNStatusType reposTextStatus, SVNStatusType reposPropStatus, long revnum, SVNLock reposLock)
throws SVNException {
Map<File, SvnStatus> statushash = fileInfo.parent.statii;
SvnStatus statstruct = statushash.get(localAbsPath);
if (statstruct == null) {
if (reposNodeStatus != SVNStatusType.STATUS_ADDED)
return;
statstruct = internalStatus(myWCContext, localAbsPath);
statstruct.setRepositoryLock(reposLock);
if (statstruct.getNodeStatus() == SVNStatusType.STATUS_UNVERSIONED || statstruct.getNodeStatus() == SVNStatusType.STATUS_NONE) {
statstruct.setWorkingCopyFormat(myAnchorStatus.getWorkingCopyFormat());
}
statushash.put(localAbsPath, statstruct);
}
if ((reposNodeStatus == SVNStatusType.STATUS_ADDED) && (statstruct.getRepositoryNodeStatus() == SVNStatusType.STATUS_DELETED))
reposNodeStatus = SVNStatusType.STATUS_REPLACED;
/* Tweak the structure's repos fields. */
if (reposNodeStatus != null)
statstruct.setRepositoryNodeStatus(reposNodeStatus);
if (reposTextStatus != null)
statstruct.setRepositoryTextStatus(reposTextStatus);
if (reposPropStatus != null)
statstruct.setRepositoryPropertiesStatus(reposPropStatus);
statstruct.setRepositoryChangedRevision(fileInfo.ood_changed_rev);
statstruct.setRepositoryChangedDate(fileInfo.ood_changed_date);
statstruct.setRepositoryKind(fileInfo.ood_kind);
statstruct.setRepositoryRootUrl(myRepositoryRoot);
statstruct.setRepositoryRelativePath(fileInfo.computeRepositoryRelativePath());
if (fileInfo.ood_changed_author != null)
statstruct.setRepositoryChangedAuthor(fileInfo.ood_changed_author);
}
private File findDirReposRelpath(DirectoryInfo dirinfo) {
/* If we have no name, we're the root, return the anchor URL. */
if (dirinfo.name == null)
return SVNFileUtil.createFilePath(myAnchorStatus.getRepositoryRelativePath());
File repos_relpath;
DirectoryInfo parent = dirinfo.parent;
SvnStatus status = parent.statii.get(dirinfo.localAbsPath);
if (status != null)
return SVNFileUtil.createFilePath(status.getRepositoryRelativePath());
repos_relpath = findDirReposRelpath(parent);
if (repos_relpath != null)
return SVNFileUtil.createFilePath(repos_relpath, dirinfo.name);
return null;
}
public void abortEdit() throws SVNException {
}
public void absentDir(String path) throws SVNException {
}
public void absentFile(String path) throws SVNException {
}
public OutputStream textDeltaChunk(String path, SVNDiffWindow diffWindow) throws SVNException {
if (diffWindow != SVNDiffWindow.EMPTY) {
myFileInfo.text_changed = true;
}
return null;
}
public void textDeltaEnd(String path) throws SVNException {
}
public void receive(SvnTarget target, SvnStatus status) throws SVNException {
if (myIsMarkingDeleted) {
status.setRepositoryNodeStatus(SVNStatusType.STATUS_DELETED);
}
getDefaultHandler().receive(target, status);
}
public SVNCommitInfo closeEdit() throws SVNException {
if (!myIsRootOpen) {
super.closeEdit();
}
return new SVNCommitInfo(getTargetRevision(), null, null);
}
private class DirectoryInfo implements ISvnObjectReceiver<SvnStatus> {
private File localAbsPath;
private String name;
private DirectoryInfo parent;
private TreeMap<File, SvnStatus> statii;
private long ood_changed_rev;
private SVNDate ood_changed_date;
private SVNNodeKind ood_kind;
private String ood_changed_author;
private boolean excluded;
private SVNDepth depth;
private boolean added;
private boolean prop_changed;
private boolean text_changed;
private String repositoryRelativePath;
public DirectoryInfo(String path, DirectoryInfo parent) throws SVNException {
File local_abspath;
SvnStatus status_in_parent;
assert (path != null || parent == null);
/* Construct the absolute path of this directory. */
if (parent != null)
local_abspath = SVNFileUtil.createFilePath(myAnchorAbsPath, path);
else
local_abspath = myAnchorAbsPath;
/* Finish populating the baton members. */
this.localAbsPath = local_abspath;
this.name = path != null ? SVNPathUtil.tail(path) : null;
this.parent = parent;
this.statii = new TreeMap<File, SvnStatus>();
this.ood_changed_rev = SVNWCContext.INVALID_REVNUM;
this.ood_changed_date = null;
this.ood_kind = SVNNodeKind.DIR;
this.ood_changed_author = null;
if (parent != null) {
if (parent.excluded)
this.excluded = true;
else if (parent.depth == SVNDepth.IMMEDIATES)
this.depth = SVNDepth.EMPTY;
else if (parent.depth == SVNDepth.FILES || parent.depth == SVNDepth.EMPTY)
this.excluded = true;
else if (parent.depth == SVNDepth.UNKNOWN)
/*
* This is only tentative, it can be overridden from d's
* entry later.
*/
this.depth = SVNDepth.UNKNOWN;
else
this.depth = SVNDepth.INFINITY;
} else {
this.depth = getDepth();
}
/*
* Get the status for this path's children. Of course, we only want
* to do this if the path is versioned as a directory.
*/
if (parent != null)
status_in_parent = parent.statii.get(this.localAbsPath);
else
status_in_parent = myAnchorStatus;
/*
* Order is important here. We can't depend on
* status_in_parent->entry being non-NULL until after we've checked
* all the conditions that might indicate that the parent is
* unversioned ("unversioned" for our purposes includes being an
* external or ignored item).
*/
if (status_in_parent != null && (status_in_parent.getNodeStatus() != SVNStatusType.STATUS_UNVERSIONED) && (status_in_parent.getNodeStatus() != SVNStatusType.STATUS_EXTERNAL)
&& (status_in_parent.getNodeStatus() != SVNStatusType.STATUS_IGNORED) && (status_in_parent.getKind() == SVNNodeKind.DIR) && (!this.excluded)
&& (this.depth == SVNDepth.UNKNOWN || this.depth == SVNDepth.INFINITY || this.depth == SVNDepth.FILES || this.depth == SVNDepth.IMMEDIATES)) {
SvnStatus this_dir_status;
Collection<String> ignores = myGlobalIgnores;
WCDbRepositoryInfo parentReposInfo = new WCDbRepositoryInfo();
parentReposInfo.rootUrl = status_in_parent.getRepositoryRootUrl();
parentReposInfo.uuid = status_in_parent.getRepositoryUuid();
getDirStatus(local_abspath, null, true, parentReposInfo, null, null, ignores,
this.depth == SVNDepth.FILES ? SVNDepth.FILES : SVNDepth.IMMEDIATES, true, true, this);
/* If we found a depth here, it should govern. */
this_dir_status = this.statii.get(this.localAbsPath);
if (this_dir_status != null && this_dir_status.isVersioned() && (this.depth == SVNDepth.UNKNOWN || this.depth.compareTo(status_in_parent.getDepth()) > 0)) {
this.depth = this_dir_status.getDepth();
}
}
}
public void receive(SvnTarget target, SvnStatus status) throws SVNException {
if (status != null) {
statii.put(status.getPath(), status);
}
}
private String computeRepositoryRelativePath() throws SVNException {
if (repositoryRelativePath != null) {
return repositoryRelativePath;
}
if (name == null) {
return myAnchorStatus.getRepositoryRelativePath();
}
SvnStatus status = (SvnStatus) parent.statii.get(localAbsPath);
if (status != null && status.getRepositoryRelativePath() != null) {
repositoryRelativePath = status.getRepositoryRelativePath();
return status.getRepositoryRelativePath();
}
String url = parent.computeRepositoryRelativePath();
if (url != null) {
url = SVNPathUtil.append(url, name);
repositoryRelativePath = url;
}
return repositoryRelativePath;
}
}
public class FileInfo {
private File localAbsPath;
private String name;
private DirectoryInfo parent;
private long ood_changed_rev;
private SVNDate ood_changed_date;
private SVNNodeKind ood_kind;
private String ood_changed_author;
private boolean added;
private boolean text_changed;
private boolean prop_changed;
private String baseChecksum;
public FileInfo(DirectoryInfo parent, String path, boolean added) {
this.localAbsPath = SVNFileUtil.createFilePath(myAnchorAbsPath, path);
this.name = SVNFileUtil.getFileName(this.localAbsPath);
this.parent = parent;
this.ood_changed_rev = SVNWCDb.INVALID_REVNUM;
this.ood_changed_date = null;
this.ood_kind = SVNNodeKind.FILE;
this.ood_changed_author = null;
}
private String computeRepositoryRelativePath() throws SVNException {
return SVNPathUtil.append(parent.computeRepositoryRelativePath(), name);
}
}
}