package org.tmatesoft.svn.core.internal.wc2.remote;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.tmatesoft.svn.core.ISVNDirEntryHandler;
import org.tmatesoft.svn.core.SVNDepth;
import org.tmatesoft.svn.core.SVNDirEntry;
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.SVNURL;
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.core.internal.wc.SVNFileUtil;
import org.tmatesoft.svn.core.internal.wc17.db.Structure;
import org.tmatesoft.svn.core.internal.wc17.db.StructureFields.NodeOriginInfo;
import org.tmatesoft.svn.core.internal.wc2.SvnRemoteOperationRunner;
import org.tmatesoft.svn.core.internal.wc2.SvnRepositoryAccess.RepositoryInfo;
import org.tmatesoft.svn.core.internal.wc2.SvnRepositoryAccess.RevisionsPair;
import org.tmatesoft.svn.core.internal.wc2.SvnWcGeneration;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc2.SvnGetProperties;
import org.tmatesoft.svn.core.wc2.SvnInheritedProperties;
import org.tmatesoft.svn.core.wc2.SvnTarget;
import org.tmatesoft.svn.util.SVNLogType;
public class SvnRemoteGetProperties extends SvnRemoteOperationRunner<SVNProperties, SvnGetProperties> {
public boolean isApplicable(SvnGetProperties operation, SvnWcGeneration wcGeneration) throws SVNException {
if (operation.isRevisionProperties()) {
return false;
}
if (super.isApplicable(operation, wcGeneration)) {
return true;
}
if (!operation.getRevision().isLocal()) {
return true;
}
return false;
}
@Override
protected SVNProperties run() throws SVNException {
SvnTarget target = getOperation().getFirstTarget();
SVNURL url;
SVNRepository repository;
long revnum;
SvnTarget reposTarget = target;
SVNRevision revision = getOperation().getRevision();
SVNRevision pegRevision = target.getResolvedPegRevision();
if (pegRevision.isLocal() && target.isFile()) {
final File localAbsPath = getOperation().getFirstTarget().getFile();
final Structure<NodeOriginInfo> origin = getWcContext().getNodeOrigin(localAbsPath, false,
NodeOriginInfo.isCopy, NodeOriginInfo.copyRootAbsPath,
NodeOriginInfo.reposRelpath, NodeOriginInfo.reposRootUrl,
NodeOriginInfo.reposUuid, NodeOriginInfo.revision);
final File reposRelPath = origin.get(NodeOriginInfo.reposRelpath);
if (reposRelPath != null) {
final SVNURL rootURL = origin.get(NodeOriginInfo.reposRootUrl);
url = rootURL.appendPath(SVNFileUtil.getFilePath(reposRelPath), false);
reposTarget = SvnTarget.fromURL(url);
Structure<RevisionsPair> revisionPair = null;
revisionPair = getRepositoryAccess().getRevisionNumber(null, target, target.getResolvedPegRevision(), revisionPair);
final long pegrevnum = revisionPair.lng(RevisionsPair.revNumber);
pegRevision = SVNRevision.create(pegrevnum);
if (getOperation().getRevision().isLocal()) {
revisionPair = getRepositoryAccess().getRevisionNumber(null, target, getOperation().getRevision(), revisionPair);
revnum = revisionPair.lng(RevisionsPair.revNumber);
revision = SVNRevision.create(revnum);
}
}
}
Structure<RepositoryInfo> repositoryInfo =
getRepositoryAccess().createRepositoryFor(
reposTarget,
revision,
pegRevision,
null);
repository = repositoryInfo.<SVNRepository>get(RepositoryInfo.repository);
revnum = repositoryInfo.lng(RepositoryInfo.revision);
url = repositoryInfo.<SVNURL>get(RepositoryInfo.url);
repositoryInfo.release();
SVNNodeKind kind = repository.checkPath("", revnum);
if (kind == SVNNodeKind.UNKNOWN) {
final SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.NODE_UNKNOWN_KIND, "Unknown node kind for ''{0}''", repository.getLocation());
SVNErrorManager.error(err, SVNLogType.WC);
} else if (kind == null || kind == SVNNodeKind.NONE) {
final SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.ENTRY_NOT_FOUND, "''{0}'' does not exist in revision {1}", repository.getLocation(), revnum);
SVNErrorManager.error(err, SVNLogType.WC);
}
if (getOperation().getTargetInheritedPropertiesReceiver() != null) {
final SVNURL repositoryRoot = repository.getRepositoryRoot(true);
final Map<String, SVNProperties> inheritedProperties = repository.getInheritedProperties("", revnum, null);
final List<SvnInheritedProperties> result = new ArrayList<SvnInheritedProperties>();
for (String path : inheritedProperties.keySet()) {
final SvnInheritedProperties propItem = new SvnInheritedProperties();
propItem.setTarget(SvnTarget.fromURL(repositoryRoot.appendPath(path, false)));
propItem.setProperties(inheritedProperties.get(path));
result.add(propItem);
}
if (!result.isEmpty()) {
getOperation().getTargetInheritedPropertiesReceiver().receive(target, result);
}
}
remotePropertyGet(url, kind, "", repository, revnum, getOperation().getDepth());
return getOperation().first();
}
private void remotePropertyGet(SVNURL url, SVNNodeKind kind, String path, SVNRepository repos, long revNumber, SVNDepth depth) throws SVNException {
SVNURL fullURL = url.appendPath(path, false);
SVNProperties props = new SVNProperties();
final Collection<SVNDirEntry> dirEntries = new LinkedList<SVNDirEntry>();
if (kind == SVNNodeKind.DIR) {
ISVNDirEntryHandler handler = SVNDepth.FILES.compareTo(depth) <= 0 ? new ISVNDirEntryHandler() {
public void handleDirEntry(SVNDirEntry dirEntry) throws SVNException {
dirEntries.add(dirEntry);
}
} : null;
repos.getDir(path, revNumber, props, SVNDirEntry.DIRENT_KIND, handler);
} else if (kind == SVNNodeKind.FILE) {
repos.getFile(path, revNumber, props, null);
} else {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.NODE_UNKNOWN_KIND, "Unknown node kind for ''{0}''", fullURL);
SVNErrorManager.error(err, SVNLogType.WC);
}
if (props != null) {
for (String name : new HashSet<String>(props.nameSet())) {
if (!SVNProperty.isRegularProperty(name)) {
props.remove(name);
}
}
if (!props.isEmpty()) {
getOperation().receive(SvnTarget.fromURL(fullURL), props);
}
}
if (depth.compareTo(SVNDepth.EMPTY) > 0 && dirEntries != null && kind == SVNNodeKind.DIR) {
for (SVNDirEntry entry : dirEntries) {
if (entry.getKind() == SVNNodeKind.FILE || depth.compareTo(SVNDepth.FILES) > 0) {
String entryPath = SVNPathUtil.append(path, entry.getName());
SVNDepth depthBelow = depth;
if (depth == SVNDepth.IMMEDIATES) {
depthBelow = SVNDepth.EMPTY;
}
remotePropertyGet(url, entry.getKind(), entryPath, repos, revNumber, depthBelow);
}
}
}
}
}