package org.tmatesoft.svn.core.internal.wc2.remote; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; 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.SVNLock; import org.tmatesoft.svn.core.SVNNodeKind; import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.internal.util.SVNDate; import org.tmatesoft.svn.core.internal.util.SVNPathUtil; import org.tmatesoft.svn.core.internal.wc.SVNErrorManager; import org.tmatesoft.svn.core.internal.wc17.db.Structure; import org.tmatesoft.svn.core.internal.wc2.SvnRemoteOperationRunner; import org.tmatesoft.svn.core.internal.wc2.SvnWcGeneration; import org.tmatesoft.svn.core.internal.wc2.SvnRepositoryAccess.LocationsInfo; import org.tmatesoft.svn.core.internal.wc2.SvnRepositoryAccess.RepositoryInfo; import org.tmatesoft.svn.core.io.SVNRepository; import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc2.SvnGetInfo; import org.tmatesoft.svn.core.wc2.SvnInfo; import org.tmatesoft.svn.core.wc2.SvnTarget; import org.tmatesoft.svn.util.SVNLogType; public class SvnRemoteGetInfo extends SvnRemoteOperationRunner<SvnInfo, SvnGetInfo> { public boolean isApplicable(SvnGetInfo operation, SvnWcGeneration wcGeneration) throws SVNException { if (super.isApplicable(operation, wcGeneration)) { return true; } SVNRevision revision = operation.getRevision(); if (!revision.isLocal()) { return true; } return false; } protected SvnInfo run() throws SVNException { SvnTarget infoTarget = getOperation().getFirstTarget(); Structure<RepositoryInfo> repositoryInfo = getRepositoryAccess().createRepositoryFor(infoTarget, getOperation().getRevision(), infoTarget.getResolvedPegRevision(), null); SVNRepository repository = repositoryInfo.<SVNRepository>get(RepositoryInfo.repository); SVNURL url = repositoryInfo.<SVNURL>get(RepositoryInfo.url); long revNum = repositoryInfo.lng(RepositoryInfo.revision); SVNURL repositoryRootUrl = repository.getRepositoryRoot(true); String repositoryUUID = repository.getRepositoryUUID(true); repositoryInfo.release(); SVNURL parentURL = url.removePathTail(); String baseName = SVNPathUtil.tail(url.getPath()); SVNDirEntry rootEntry = null; SVNDepth depth = getOperation().getDepth(); SVNRevision pegRevision = infoTarget.getResolvedPegRevision(); try { rootEntry = repository.info("", revNum); } catch (SVNException e) { if (e.getErrorMessage() != null && e.getErrorMessage().getErrorCode() == SVNErrorCode.RA_NOT_IMPLEMENTED) { if (url.equals(repositoryRootUrl)) { if (depth.compareTo(SVNDepth.EMPTY) > 0) { SVNLock[] locks = null; if (pegRevision == SVNRevision.HEAD) { try { locks = repository.getLocks(""); } catch (SVNException svne) { SVNErrorCode code = svne.getErrorMessage().getErrorCode(); if (code == SVNErrorCode.RA_NOT_IMPLEMENTED || code == SVNErrorCode.UNSUPPORTED_FEATURE) { locks = new SVNLock[0]; } else { throw svne; } } } else { locks = new SVNLock[0]; } locks = locks == null ? new SVNLock[0] : locks; Map<String, SVNLock> locksMap = new HashMap<String, SVNLock>(); for (int i = 0; i < locks.length; i++) { SVNLock lock = locks[i]; locksMap.put(lock.getPath(), lock); } pushDirInfo(repository, SVNRevision.create(revNum), "", repository.getRepositoryRoot(true), repositoryUUID, url, locksMap, depth); return getOperation().first(); } SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.UNSUPPORTED_FEATURE, "Server does not support retrieving information about the repository root"); SVNErrorManager.error(err, SVNLogType.WC); } SVNNodeKind urlKind = repository.checkPath("", revNum); if (urlKind == SVNNodeKind.NONE) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.RA_ILLEGAL_URL, "URL ''{0}'' non-existent in revision {1}", new Object[] { url, new Long(revNum) }); SVNErrorManager.error(err, SVNLogType.WC); } SVNRepository parentRepository = getRepositoryAccess().createRepository(parentURL, null, false); Collection<SVNDirEntry> dirEntries = parentRepository.getDir("", revNum, null, SVNDirEntry.DIRENT_KIND | SVNDirEntry.DIRENT_CREATED_REVISION | SVNDirEntry.DIRENT_TIME | SVNDirEntry.DIRENT_LAST_AUTHOR, (Collection<SVNDirEntry>) null); for (SVNDirEntry dirEntry : dirEntries) { if (baseName.equals(dirEntry.getName())) { rootEntry = dirEntry; break; } } if (rootEntry == null) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.RA_ILLEGAL_URL, "URL ''{0}'' non-existent in revision {1}", new Object[] { url, new Long(revNum)}); SVNErrorManager.error(err, SVNLogType.WC); } } else { throw e; } } if (rootEntry == null || rootEntry.getKind() == SVNNodeKind.NONE) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.RA_ILLEGAL_URL, "URL ''{0}'' non-existent in revision {1}", new Object[] { url, new Long(revNum) }); SVNErrorManager.error(err, SVNLogType.WC); } SVNLock lock = null; if (rootEntry.getKind() == SVNNodeKind.FILE) { try { Structure<LocationsInfo> locations = getRepositoryAccess().getLocations(null, SvnTarget.fromURL(url), SVNRevision.create(revNum), SVNRevision.HEAD, SVNRevision.UNDEFINED); if (locations != null && locations.hasValue(LocationsInfo.startUrl)) { SVNURL headURL = locations.<SVNURL>get(LocationsInfo.startUrl); locations.release(); if (headURL.equals(url)) { try { lock = repository.getLock(""); } catch (SVNException e) { if (!(e.getErrorMessage() != null && e.getErrorMessage().getErrorCode() == SVNErrorCode.RA_NOT_IMPLEMENTED)) { throw e; } } } } } catch (SVNException e) { SVNErrorCode code = e.getErrorMessage().getErrorCode(); if (code != SVNErrorCode.FS_NOT_FOUND && code != SVNErrorCode.CLIENT_UNRELATED_RESOURCES) { throw e; } } } SvnInfo info = creatSvnInfoForEntry(repositoryRootUrl, repositoryUUID, rootEntry, url, revNum, lock); getOperation().receive(SvnTarget.fromURL(url), info); if (depth.compareTo(SVNDepth.EMPTY) > 0 && rootEntry.getKind() == SVNNodeKind.DIR) { SVNLock[] locks = null; if (pegRevision == SVNRevision.HEAD) { try { locks = repository.getLocks(""); } catch (SVNException svne) { SVNErrorCode code = svne.getErrorMessage().getErrorCode(); if (code == SVNErrorCode.RA_NOT_IMPLEMENTED || code == SVNErrorCode.UNSUPPORTED_FEATURE) { locks = new SVNLock[0]; } else { throw svne; } } } else { locks = new SVNLock[0]; } locks = locks == null ? new SVNLock[0] : locks; Map<String, SVNLock> locksMap = new HashMap<String, SVNLock>(); for (int i = 0; i < locks.length; i++) { lock = locks[i]; locksMap.put(lock.getPath(), lock); } pushDirInfo(repository, SVNRevision.create(revNum), "", repository.getRepositoryRoot(true), repositoryUUID, url, locksMap, depth); } return getOperation().first(); } private void pushDirInfo(SVNRepository repos, SVNRevision rev, String dir, SVNURL root, String uuid, SVNURL url, Map<String, SVNLock> locks, SVNDepth depth) throws SVNException { Collection<SVNDirEntry> children = repos.getDir(dir, rev.getNumber(), null, SVNDirEntry.DIRENT_SIZE | SVNDirEntry.DIRENT_KIND | SVNDirEntry.DIRENT_CREATED_REVISION | SVNDirEntry.DIRENT_TIME | SVNDirEntry.DIRENT_LAST_AUTHOR, new ArrayList<SVNDirEntry>()); for (SVNDirEntry child : children) { SVNURL childURL = url.appendPath(child.getName(), false); String path = SVNPathUtil.append(dir, child.getName()); String fsPath = "/" + SVNPathUtil.getRelativePath(root.toDecodedString(), childURL.toDecodedString()); SVNLock lock = locks.get(fsPath); if (depth.compareTo(SVNDepth.IMMEDIATES) >= 0 || (depth == SVNDepth.FILES && child.getKind() == SVNNodeKind.FILE)) { SvnInfo info = creatSvnInfoForEntry(root, uuid, child, childURL, rev.getNumber(), lock); getOperation().receive(SvnTarget.fromURL(childURL), info); } if (depth == SVNDepth.INFINITY && child.getKind() == SVNNodeKind.DIR) { pushDirInfo(repos, rev, path, root, uuid, childURL, locks, depth); } } } private SvnInfo creatSvnInfoForEntry(SVNURL root, String uuid, SVNDirEntry entry, SVNURL entryURL, long revision, SVNLock lock) { SvnInfo info = new SvnInfo(); info.setKind(entry.getKind()); info.setLastChangedAuthor(entry.getAuthor()); info.setLastChangedDate(SVNDate.fromDate(entry.getDate())); info.setLastChangedRevision(entry.getRevision()); info.setLock(lock); info.setRepositoryRootURL(root); info.setRepositoryUuid(uuid); info.setSize(entry.getSize()); info.setUrl(entryURL); info.setRevision(revision); return info; } }