0001: /*
0002: * ====================================================================
0003: * Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
0004: *
0005: * This software is licensed as described in the file COPYING, which
0006: * you should have received as part of this distribution. The terms
0007: * are also available at http://svnkit.com/license.html.
0008: * If newer versions of this license are posted there, you may use a
0009: * newer version instead, at your option.
0010: * ====================================================================
0011: */
0012: package org.tmatesoft.svn.core.wc.admin;
0013:
0014: import java.io.File;
0015: import java.io.IOException;
0016: import java.io.InputStream;
0017: import java.io.OutputStream;
0018: import java.util.Date;
0019: import java.util.Iterator;
0020: import java.util.Map;
0021:
0022: import org.tmatesoft.svn.core.SVNErrorCode;
0023: import org.tmatesoft.svn.core.SVNErrorMessage;
0024: import org.tmatesoft.svn.core.SVNException;
0025: import org.tmatesoft.svn.core.SVNLock;
0026: import org.tmatesoft.svn.core.SVNLogEntry;
0027: import org.tmatesoft.svn.core.SVNNodeKind;
0028: import org.tmatesoft.svn.core.SVNRevisionProperty;
0029: import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
0030: import org.tmatesoft.svn.core.internal.delta.SVNDeltaCombiner;
0031: import org.tmatesoft.svn.core.internal.io.fs.FSEntry;
0032: import org.tmatesoft.svn.core.internal.io.fs.FSFS;
0033: import org.tmatesoft.svn.core.internal.io.fs.FSID;
0034: import org.tmatesoft.svn.core.internal.io.fs.FSNodeHistory;
0035: import org.tmatesoft.svn.core.internal.io.fs.FSRepositoryUtil;
0036: import org.tmatesoft.svn.core.internal.io.fs.FSRevisionNode;
0037: import org.tmatesoft.svn.core.internal.io.fs.FSRevisionRoot;
0038: import org.tmatesoft.svn.core.internal.io.fs.FSRoot;
0039: import org.tmatesoft.svn.core.internal.io.fs.FSTransactionInfo;
0040: import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
0041: import org.tmatesoft.svn.core.internal.util.SVNTimeUtil;
0042: import org.tmatesoft.svn.core.internal.wc.DefaultSVNGNUDiffGenerator;
0043: import org.tmatesoft.svn.core.internal.wc.SVNAdminHelper;
0044: import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
0045: import org.tmatesoft.svn.core.internal.wc.SVNFileUtil;
0046: import org.tmatesoft.svn.core.internal.wc.SVNNodeEditor;
0047: import org.tmatesoft.svn.core.wc.ISVNOptions;
0048: import org.tmatesoft.svn.core.wc.ISVNRepositoryPool;
0049: import org.tmatesoft.svn.core.wc.SVNBasicClient;
0050: import org.tmatesoft.svn.core.wc.SVNRevision;
0051:
0052: /**
0053: * The <b>SVNLookClient</b> class provides API for examining
0054: * different aspects of a Subversion repository. Its functionality
0055: * is similar to the one of the Subversion command-line utility
0056: * called <i>svnlook</i>. The following table matches methods of
0057: * <b>SVNLookClient</b> to the corresponding commands of the
0058: * <i>svnlook</i> utility (to make sense what its different methods
0059: * are for):
0060: *
0061: * <table cellpadding="3" cellspacing="1" border="0" width="50%" bgcolor="#999933">
0062: * <tr bgcolor="#ADB8D9" align="left">
0063: * <td><b>SVNLookClient</b></td>
0064: * <td><b>Subversion</b></td>
0065: * </tr>
0066: * <tr bgcolor="#EAEAEA" align="left">
0067: * <td>doCat()</td><td>'svnlook cat'</td>
0068: * </tr>
0069: * <tr bgcolor="#EAEAEA" align="left">
0070: * <td>doGetAuthor()</td><td>'svnlook author'</td>
0071: * </tr>
0072: * <tr bgcolor="#EAEAEA" align="left">
0073: * <td>doGetChanged()</td><td>'svnlook changed'</td>
0074: * </tr>
0075: * <tr bgcolor="#EAEAEA" align="left">
0076: * <td>doGetChangedDirectories()</td><td>'svnlook dirs-changed'</td>
0077: * </tr>
0078: * <tr bgcolor="#EAEAEA" align="left">
0079: * <td>doGetDate()</td><td>'svnlook date'</td>
0080: * </tr>
0081: * <tr bgcolor="#EAEAEA" align="left">
0082: * <td>doGetDiff()</td><td>'svnlook diff'</td>
0083: * </tr>
0084: * <tr bgcolor="#EAEAEA" align="left">
0085: * <td>doGetHistory()</td><td>'svnlook history'</td>
0086: * </tr>
0087: * <tr bgcolor="#EAEAEA" align="left">
0088: * <td>doGetInfo()</td><td>'svnlook info'</td>
0089: * </tr>
0090: * <tr bgcolor="#EAEAEA" align="left">
0091: * <td>doGetLock()</td><td>'svnlook lock'</td>
0092: * </tr>
0093: * <tr bgcolor="#EAEAEA" align="left">
0094: * <td>doGetLog()</td><td>'svnlook log'</td>
0095: * </tr>
0096: * <tr bgcolor="#EAEAEA" align="left">
0097: * <td>doGetProperties()</td><td>'svnlook proplist'</td>
0098: * </tr>
0099: * <tr bgcolor="#EAEAEA" align="left">
0100: * <td>doGetProperty()</td><td>'svnlook propget'</td>
0101: * </tr>
0102: * <tr bgcolor="#EAEAEA" align="left">
0103: * <td>doGetRevisionProperties()</td><td>'svnlook proplist --revprop'</td>
0104: * </tr>
0105: * <tr bgcolor="#EAEAEA" align="left">
0106: * <td>doGetRevisionProperty()</td><td>'svnlook propget --revprop'</td>
0107: * </tr>
0108: * <tr bgcolor="#EAEAEA" align="left">
0109: * <td>doGetTree()</td><td>'svnlook tree'</td>
0110: * </tr>
0111: * <tr bgcolor="#EAEAEA" align="left">
0112: * <td>doGetUUID()</td><td>'svnlook uuid'</td>
0113: * </tr>
0114: * <tr bgcolor="#EAEAEA" align="left">
0115: * <td>doGetYoungestRevision()</td><td>'svnlook youngest'</td>
0116: * </tr>
0117: * </table>
0118: *
0119: * @version 1.1.1
0120: * @author TMate Software Ltd.
0121: * @since 1.1.1
0122: */
0123: public class SVNLookClient extends SVNBasicClient {
0124: private ISVNGNUDiffGenerator myDiffGenerator;
0125:
0126: /**
0127: * Creates a new instance of <b>SVNLookClient</b>
0128: * given an authentication manager and global
0129: * options keeper.
0130: *
0131: * @param authManager a manager which provides authentication
0132: * credentials
0133: * @param options a global config options provider
0134: */
0135: public SVNLookClient(ISVNAuthenticationManager authManager,
0136: ISVNOptions options) {
0137: super (authManager, options);
0138: }
0139:
0140: /**
0141: * Creates a new instance of <b>SVNLookClient</b>
0142: * given an {@link org.tmatesoft.svn.core.io.SVNRepository}}
0143: * drivers provider and global options keeper.
0144: *
0145: * @param repositoryPool a repository connectors keeper
0146: * @param options a global config options provider
0147: */
0148: public SVNLookClient(ISVNRepositoryPool repositoryPool,
0149: ISVNOptions options) {
0150: super (repositoryPool, options);
0151: }
0152:
0153: /**
0154: * Retrieves author, timestamp and log message information from
0155: * the repository for the given revision. This information is
0156: * provided in a single {@link org.tmatesoft.svn.core.SVNLogEntry}
0157: * object, that is only the following methods of <b>SVNLogEntry</b>
0158: * return valid information:
0159: *
0160: * <ul>
0161: * <li>
0162: * {@link org.tmatesoft.svn.core.SVNLogEntry#getAuthor() getAuthor()}
0163: * </li>
0164: * <li>
0165: * {@link org.tmatesoft.svn.core.SVNLogEntry#getDate() getDate()}
0166: * </li>
0167: * <li>
0168: * {@link org.tmatesoft.svn.core.SVNLogEntry#getMessage() getMessage()}
0169: * </li>
0170: * <li>
0171: * {@link org.tmatesoft.svn.core.SVNLogEntry#getRevision() getRevision()}
0172: * </li>
0173: * </ul>
0174: *
0175: * @param repositoryRoot a repository root directory path
0176: * @param revision a revision number
0177: * @return revision info
0178: * @throws SVNException no repository is found at
0179: * <code>repositoryRoot</code>
0180: */
0181: public SVNLogEntry doGetInfo(File repositoryRoot,
0182: SVNRevision revision) throws SVNException {
0183: FSFS fsfs = open(repositoryRoot, revision);
0184: long revNum = SVNAdminHelper.getRevisionNumber(revision, fsfs
0185: .getYoungestRevision(), fsfs);
0186: Map revProps = fsfs.getRevisionProperties(revNum);
0187: String date = (String) revProps.get(SVNRevisionProperty.DATE);
0188: String author = (String) revProps
0189: .get(SVNRevisionProperty.AUTHOR);
0190: String logMessage = (String) revProps
0191: .get(SVNRevisionProperty.LOG);
0192: return new SVNLogEntry(null, revNum, author, SVNTimeUtil
0193: .parseDateString(date), logMessage);
0194: }
0195:
0196: /**
0197: * Retrieves author, timestamp and log message information from
0198: * the repository for the given transaction name. This information is
0199: * provided in a single {@link org.tmatesoft.svn.core.SVNLogEntry}
0200: * object, that is only the following methods of <b>SVNLogEntry</b>
0201: * return valid information:
0202: * <ul>
0203: * <li>
0204: * {@link org.tmatesoft.svn.core.SVNLogEntry#getAuthor() getAuthor()}
0205: * </li>
0206: * <li>
0207: * {@link org.tmatesoft.svn.core.SVNLogEntry#getDate() getDate()}
0208: * </li>
0209: * <li>
0210: * {@link org.tmatesoft.svn.core.SVNLogEntry#getMessage() getMessage()}
0211: * </li>
0212: * </ul>
0213: *
0214: * @param repositoryRoot a repository root directory path
0215: * @param transactionName a transaction name
0216: * @return transaction info
0217: * @throws SVNException <ul>
0218: * <li>no repository is found at
0219: * <code>repositoryRoot</code></li>
0220: * <li>if the specified transaction is not found</li>
0221: * </ul>
0222: */
0223: public SVNLogEntry doGetInfo(File repositoryRoot,
0224: String transactionName) throws SVNException {
0225: FSFS fsfs = open(repositoryRoot, transactionName);
0226: FSTransactionInfo txn = fsfs.openTxn(transactionName);
0227:
0228: Map txnProps = fsfs.getTransactionProperties(txn.getTxnId());
0229: String date = (String) txnProps.get(SVNRevisionProperty.DATE);
0230: String author = (String) txnProps
0231: .get(SVNRevisionProperty.AUTHOR);
0232: String logMessage = (String) txnProps
0233: .get(SVNRevisionProperty.LOG);
0234: return new SVNLogEntry(null, -1, author, SVNTimeUtil
0235: .parseDateString(date), logMessage);
0236: }
0237:
0238: /**
0239: * Returns the latest revision of the repository.
0240: *
0241: * @param repositoryRoot a repository root directory path
0242: * @return a revision number
0243: * @throws SVNException no repository is found at
0244: * <code>repositoryRoot</code>
0245: */
0246: public long doGetYoungestRevision(File repositoryRoot)
0247: throws SVNException {
0248: FSFS fsfs = SVNAdminHelper.openRepository(repositoryRoot);
0249: return fsfs.getYoungestRevision();
0250: }
0251:
0252: /**
0253: * Returns the uuid of the repository.
0254: *
0255: * @param repositoryRoot a repository root directory path
0256: * @return an uuid
0257: * @throws SVNException no repository is found at
0258: * <code>repositoryRoot</code>
0259: */
0260: public String doGetUUID(File repositoryRoot) throws SVNException {
0261: FSFS fsfs = SVNAdminHelper.openRepository(repositoryRoot);
0262: return fsfs.getUUID();
0263: }
0264:
0265: /**
0266: * Returns author information for the given revision.
0267: *
0268: * @param repositoryRoot a repository root directory path
0269: * @param revision a revision number
0270: * @return a revision author
0271: * @throws SVNException no repository is found at
0272: * <code>repositoryRoot</code>
0273: */
0274: public String doGetAuthor(File repositoryRoot, SVNRevision revision)
0275: throws SVNException {
0276: FSFS fsfs = open(repositoryRoot, revision);
0277: long revNum = SVNAdminHelper.getRevisionNumber(revision, fsfs
0278: .getYoungestRevision(), fsfs);
0279: Map revProps = fsfs.getRevisionProperties(revNum);
0280: return (String) revProps.get(SVNRevisionProperty.AUTHOR);
0281: }
0282:
0283: /**
0284: * Returns author information for the given transaction.
0285: *
0286: * @param repositoryRoot a repository root directory path
0287: * @param transactionName a transaction name
0288: * @return a transaction owner
0289: * @throws SVNException <ul>
0290: * <li>no repository is found at
0291: * <code>repositoryRoot</code></li>
0292: * <li>if the specified transaction is not found</li>
0293: * </ul>
0294: */
0295: public String doGetAuthor(File repositoryRoot,
0296: String transactionName) throws SVNException {
0297: FSFS fsfs = open(repositoryRoot, transactionName);
0298: FSTransactionInfo txn = fsfs.openTxn(transactionName);
0299: Map txnProps = fsfs.getTransactionProperties(txn.getTxnId());
0300: return (String) txnProps.get(SVNRevisionProperty.AUTHOR);
0301: }
0302:
0303: /**
0304: * Fetches file contents for the specified revision and path.
0305: * <code>path</code> must be absolute, that is it must
0306: * start with <code>'/'</code>. The provided output stream is
0307: * not closed within this method.
0308: *
0309: * @param repositoryRoot a repository root directory path
0310: * @param path an absolute file path
0311: * @param revision a revision number
0312: * @param out an output stream to write contents to
0313: * @throws SVNException <ul>
0314: * <li>no repository is found at
0315: * <code>repositoryRoot</code>
0316: * </li>
0317: * <li>if <code>path</code> is not found or
0318: * is not a file
0319: * </li>
0320: * </ul>
0321: */
0322: public void doCat(File repositoryRoot, String path,
0323: SVNRevision revision, OutputStream out) throws SVNException {
0324: if (path == null) {
0325: SVNErrorMessage err = SVNErrorMessage.create(
0326: SVNErrorCode.CL_INSUFFICIENT_ARGS,
0327: "Missing repository path argument");
0328: SVNErrorManager.error(err);
0329: }
0330:
0331: FSFS fsfs = open(repositoryRoot, revision);
0332: long revNum = SVNAdminHelper.getRevisionNumber(revision, fsfs
0333: .getYoungestRevision(), fsfs);
0334: FSRoot root = fsfs.createRevisionRoot(revNum);
0335: catFile(root, path, out);
0336: }
0337:
0338: /**
0339: * Fetches file contents for the specified path in the given
0340: * transaction. <code>path</code> must be absolute, that is it
0341: * must start with <code>'/'</code>. The provided output stream
0342: * is not closed within this method.
0343: *
0344: * @param repositoryRoot a repository root directory path
0345: * @param path an absolute file path
0346: * @param transactionName a transaction name
0347: * @param out an output stream to write contents to
0348: * @throws SVNException <ul>
0349: * <li>no repository is found at
0350: * <code>repositoryRoot</code>
0351: * </li>
0352: * <li>if <code>path</code> is not found or
0353: * is not a file
0354: * </li>
0355: * <li>if the specified transaction is not found
0356: * </li>
0357: * </ul>
0358: */
0359: public void doCat(File repositoryRoot, String path,
0360: String transactionName, OutputStream out)
0361: throws SVNException {
0362: if (path == null) {
0363: SVNErrorMessage err = SVNErrorMessage.create(
0364: SVNErrorCode.CL_INSUFFICIENT_ARGS,
0365: "Missing repository path argument");
0366: SVNErrorManager.error(err);
0367: }
0368:
0369: FSFS fsfs = open(repositoryRoot, transactionName);
0370: FSTransactionInfo txn = fsfs.openTxn(transactionName);
0371: FSRoot root = fsfs.createTransactionRoot(txn.getTxnId());
0372: catFile(root, path, out);
0373: }
0374:
0375: /**
0376: * Returns datestamp information for the given revision.
0377: *
0378: * @param repositoryRoot a repository root directory path
0379: * @param revision a revision number
0380: * @return a datestamp
0381: * @throws SVNException no repository is found at
0382: * <code>repositoryRoot</code>
0383: */
0384: public Date doGetDate(File repositoryRoot, SVNRevision revision)
0385: throws SVNException {
0386: FSFS fsfs = open(repositoryRoot, revision);
0387: long revNum = SVNAdminHelper.getRevisionNumber(revision, fsfs
0388: .getYoungestRevision(), fsfs);
0389: Map revProps = fsfs.getRevisionProperties(revNum);
0390: String date = (String) revProps.get(SVNRevisionProperty.DATE);
0391: if (date != null) {
0392: return SVNTimeUtil.parseDate(date);
0393: }
0394: return null;
0395: }
0396:
0397: /**
0398: * Returns datestamp information for the given transaction.
0399: *
0400: * @param repositoryRoot a repository root directory path
0401: * @param transactionName a transaction name
0402: * @return a datestamp
0403: * @throws SVNException <ul>
0404: * <li>no repository is found at
0405: * <code>repositoryRoot</code>
0406: * </li>
0407: * <li>if the specified transaction is not found
0408: * </li>
0409: * </ul>
0410: */
0411: public Date doGetDate(File repositoryRoot, String transactionName)
0412: throws SVNException {
0413: FSFS fsfs = open(repositoryRoot, transactionName);
0414: FSTransactionInfo txn = fsfs.openTxn(transactionName);
0415: Map txnProps = fsfs.getTransactionProperties(txn.getTxnId());
0416: String date = (String) txnProps.get(SVNRevisionProperty.DATE);
0417: if (date != null) {
0418: return SVNTimeUtil.parseDate(date);
0419: }
0420: return null;
0421: }
0422:
0423: /**
0424: * Returns log information for the given revision.
0425: *
0426: * @param repositoryRoot a repository root directory path
0427: * @param revision a revision number
0428: * @return a log message
0429: * @throws SVNException no repository is found at
0430: * <code>repositoryRoot</code>
0431: */
0432: public String doGetLog(File repositoryRoot, SVNRevision revision)
0433: throws SVNException {
0434: FSFS fsfs = open(repositoryRoot, revision);
0435: long revNum = SVNAdminHelper.getRevisionNumber(revision, fsfs
0436: .getYoungestRevision(), fsfs);
0437: Map revProps = fsfs.getRevisionProperties(revNum);
0438: return (String) revProps.get(SVNRevisionProperty.LOG);
0439: }
0440:
0441: /**
0442: * Returns log information for the given transaction.
0443: *
0444: * @param repositoryRoot a repository root directory path
0445: * @param transactionName a transaction name
0446: * @return a log message
0447: * @throws SVNException <ul>
0448: * <li>no repository is found at
0449: * <code>repositoryRoot</code>
0450: * </li>
0451: * <li>if the specified transaction is not found
0452: * </li>
0453: * </ul>
0454: */
0455: public String doGetLog(File repositoryRoot, String transactionName)
0456: throws SVNException {
0457: FSFS fsfs = open(repositoryRoot, transactionName);
0458: FSTransactionInfo txn = fsfs.openTxn(transactionName);
0459: Map txnProps = fsfs.getTransactionProperties(txn.getTxnId());
0460: return (String) txnProps.get(SVNRevisionProperty.LOG);
0461: }
0462:
0463: /**
0464: * Traverses changed paths for the given revision invoking
0465: * the passed handler on each changed path.
0466: *
0467: * @param repositoryRoot a repository root directory path
0468: * @param revision a revision number
0469: * @param handler a changed path handler
0470: * @param includeCopyInfo if <span class="javakeyword">true</span> copy-from
0471: * information is also provided for copied paths
0472: * @throws SVNException no repository is found at
0473: * <code>repositoryRoot</code>
0474: */
0475: public void doGetChanged(File repositoryRoot, SVNRevision revision,
0476: ISVNChangeEntryHandler handler, boolean includeCopyInfo)
0477: throws SVNException {
0478: FSFS fsfs = open(repositoryRoot, revision);
0479: long revNum = SVNAdminHelper.getRevisionNumber(revision, fsfs
0480: .getYoungestRevision(), fsfs);
0481: FSRoot root = fsfs.createRevisionRoot(revNum);
0482: long baseRevision = revNum - 1;
0483: SVNNodeEditor editor = generateDeltaTree(fsfs, root,
0484: baseRevision);
0485: editor.traverseTree(includeCopyInfo, handler);
0486: }
0487:
0488: /**
0489: * Traverses changed paths for the given transaction invoking
0490: * the passed handler on each changed path.
0491: *
0492: * @param repositoryRoot a repository root directory path
0493: * @param transactionName a transaction name
0494: * @param handler a changed path handler
0495: * @param includeCopyInfo if <span class="javakeyword">true</span> copy-from
0496: * information is also provided for copied paths
0497: * @throws SVNException <ul>
0498: * <li>no repository is found at
0499: * <code>repositoryRoot</code>
0500: * </li>
0501: * <li>if the specified transaction is not found
0502: * </li>
0503: * </ul>
0504: */
0505: public void doGetChanged(File repositoryRoot,
0506: String transactionName, ISVNChangeEntryHandler handler,
0507: boolean includeCopyInfo) throws SVNException {
0508: FSFS fsfs = open(repositoryRoot, transactionName);
0509: FSTransactionInfo txn = fsfs.openTxn(transactionName);
0510: FSRoot root = fsfs.createTransactionRoot(txn.getTxnId());
0511: long baseRevision = txn.getBaseRevision();
0512:
0513: if (!SVNRevision.isValidRevisionNumber(baseRevision)) {
0514: SVNErrorMessage err = SVNErrorMessage
0515: .create(
0516: SVNErrorCode.FS_NO_SUCH_REVISION,
0517: "Transaction ''{0}'' is not based on a revision; how odd",
0518: transactionName);
0519: SVNErrorManager.error(err);
0520: }
0521: SVNNodeEditor editor = generateDeltaTree(fsfs, root,
0522: baseRevision);
0523: editor.traverseTree(includeCopyInfo, handler);
0524: }
0525:
0526: /**
0527: * Passes paths of directories changed in the given revision to the provided handler.
0528: * Paths are absolute (start with <code>'/'</code>).
0529: *
0530: * @param repositoryRoot a repository root directory path
0531: * @param revision a revision number
0532: * @param handler a path handler
0533: * @throws SVNException no repository is found at
0534: * <code>repositoryRoot</code>
0535: */
0536: public void doGetChangedDirectories(File repositoryRoot,
0537: SVNRevision revision, ISVNChangedDirectoriesHandler handler)
0538: throws SVNException {
0539: FSFS fsfs = open(repositoryRoot, revision);
0540: long revNum = SVNAdminHelper.getRevisionNumber(revision, fsfs
0541: .getYoungestRevision(), fsfs);
0542: FSRoot root = fsfs.createRevisionRoot(revNum);
0543: long baseRevision = revNum - 1;
0544: SVNNodeEditor editor = generateDeltaTree(fsfs, root,
0545: baseRevision);
0546: editor.traverseChangedDirs(handler);
0547: }
0548:
0549: /**
0550: * Passes paths of directories changed in the given transaction to the provided handler.
0551: * Paths are absolute (start with <code>'/'</code>).
0552: *
0553: * @param repositoryRoot a repository root directory path
0554: * @param transactionName a transaction name
0555: * @param handler a path handler
0556: * @throws SVNException <ul>
0557: * <li>no repository is found at
0558: * <code>repositoryRoot</code>
0559: * </li>
0560: * <li>if the specified transaction is not found
0561: * </li>
0562: * </ul>
0563: */
0564: public void doGetChangedDirectories(File repositoryRoot,
0565: String transactionName,
0566: ISVNChangedDirectoriesHandler handler) throws SVNException {
0567: FSFS fsfs = open(repositoryRoot, transactionName);
0568: FSTransactionInfo txn = fsfs.openTxn(transactionName);
0569: FSRoot root = fsfs.createTransactionRoot(txn.getTxnId());
0570: long baseRevision = txn.getBaseRevision();
0571:
0572: if (!SVNRevision.isValidRevisionNumber(baseRevision)) {
0573: SVNErrorMessage err = SVNErrorMessage
0574: .create(
0575: SVNErrorCode.FS_NO_SUCH_REVISION,
0576: "Transaction ''{0}'' is not based on a revision; how odd",
0577: transactionName);
0578: SVNErrorManager.error(err);
0579: }
0580: SVNNodeEditor editor = generateDeltaTree(fsfs, root,
0581: baseRevision);
0582: editor.traverseChangedDirs(handler);
0583: }
0584:
0585: /**
0586: * Passes history information for the specified path and revision to the provided handler.
0587: * This information is provided as {@link SVNAdminPath} objects and include the following
0588: * pieces:
0589: * <ul>
0590: * <li>path (use {@link SVNAdminPath#getPath()} to retrieve it)</li>
0591: * <li>revision (use {@link SVNAdminPath#getRevision()} to retrieve it)</li>
0592: * <li>node id (optional, use {@link SVNAdminPath#getNodeID()} to retrieve it)</li>
0593: * </ul>
0594: * For history retrieval only these listed <code>get</code> methods of <b>SVNAdminPath</b> are
0595: * relevant.
0596: *
0597: * <p>
0598: * <code>path</code> must be absolute, that is it must start with <code>'/'</code>.
0599: * If <code>path</code> is <span class="javakeyword">null</span> it defaults to
0600: * <code>"/"</code>.
0601: *
0602: * @param repositoryRoot a repository root directory path
0603: * @param path an absolute path
0604: * @param revision a revision number
0605: * @param includeIDs if <span class="javakeyword">true</span> a node
0606: * revision id is also included for each path
0607: * @param handler a history handler
0608: * @throws SVNException <ul>
0609: * <li>no repository is found at
0610: * <code>repositoryRoot</code>
0611: * </li>
0612: * <li>if <code>path</code> is not found
0613: * </li>
0614: * </ul>
0615: */
0616: public void doGetHistory(File repositoryRoot, String path,
0617: SVNRevision revision, boolean includeIDs,
0618: ISVNHistoryHandler handler) throws SVNException {
0619: FSFS fsfs = open(repositoryRoot, revision);
0620: long revNum = SVNAdminHelper.getRevisionNumber(revision, fsfs
0621: .getYoungestRevision(), fsfs);
0622: path = path == null ? "/" : path;
0623: getHistory(fsfs, path, 0, revNum, true, includeIDs, handler);
0624: }
0625:
0626: /**
0627: * Retrieves lock information for the specified path.
0628: * <code>path</code> must be absolute, that is it must start with <code>'/'</code>.
0629: *
0630: * @param repositoryRoot a repository root directory path
0631: * @param path an absolute path
0632: * @return an object containing details of a lock or
0633: * <span class="javakeyword">null</span> if the
0634: * path is not locked
0635: * @throws SVNException <ul>
0636: * <li>no repository is found at
0637: * <code>repositoryRoot</code>
0638: * </li>
0639: * <li>if <code>path</code> is not found
0640: * </li>
0641: * </ul>
0642: */
0643: public SVNLock doGetLock(File repositoryRoot, String path)
0644: throws SVNException {
0645: if (path == null) {
0646: SVNErrorMessage err = SVNErrorMessage.create(
0647: SVNErrorCode.CL_INSUFFICIENT_ARGS,
0648: "Missing path argument");
0649: SVNErrorManager.error(err);
0650: }
0651: FSFS fsfs = open(repositoryRoot, SVNRevision.HEAD);
0652: return fsfs.getLockHelper(path, false);
0653: }
0654:
0655: /**
0656: * Traverses repository tree starting at the specified path in the
0657: * given revision and invoking the provided handler on each path.
0658: * Path information is provided as {@link SVNAdminPath} objects and
0659: * include the following pieces:
0660: * <ul>
0661: * <li>path (use {@link SVNAdminPath#getPath()} to retrieve it)</li>
0662: * <li>tree depth (use {@link SVNAdminPath#getTreeDepth()} to retrieve it)</li>
0663: * <li>node id (optional, use {@link SVNAdminPath#getNodeID()} to retrieve it)</li>
0664: * <li>file/dir information (use {@link SVNAdminPath#isDir()} to retrieve it)</li>
0665: * </ul>
0666: *
0667: * For tree retrieval only these listed <code>get</code> methods of <b>SVNAdminPath</b> are
0668: * relevant.
0669: *
0670: * <p>
0671: * <code>path</code> must be absolute, that is it must start with <code>'/'</code>.
0672: * If <code>path</code> is <span class="javakeyword">null</span> it defaults to
0673: * <code>"/"</code>.
0674: *
0675: * @param repositoryRoot a repository root directory path
0676: * @param path an absolute path
0677: * @param revision a revision number
0678: * @param includeIDs if <span class="javakeyword">true</span> a node
0679: * revision id is also included for each path
0680: * @param handler a tree handler
0681: * @throws SVNException <ul>
0682: * <li>no repository is found at
0683: * <code>repositoryRoot</code>
0684: * </li>
0685: * <li>if <code>path</code> is not found
0686: * </li>
0687: * </ul>
0688: */
0689: public void doGetTree(File repositoryRoot, String path,
0690: SVNRevision revision, boolean includeIDs,
0691: ISVNTreeHandler handler) throws SVNException {
0692: FSFS fsfs = open(repositoryRoot, revision);
0693: long revNum = SVNAdminHelper.getRevisionNumber(revision, fsfs
0694: .getYoungestRevision(), fsfs);
0695: FSRoot root = fsfs.createRevisionRoot(revNum);
0696: path = path == null ? "/" : path;
0697: FSRevisionNode node = root.getRevisionNode(path);
0698: FSID id = includeIDs ? node.getId() : null;
0699: SVNNodeKind kind = root.checkNodeKind(path);
0700: getTree(fsfs, root, path, kind, id, includeIDs, 0, handler);
0701: }
0702:
0703: /**
0704: * Traverses repository tree starting at the specified path in the
0705: * given transaction and invoking the provided handler on each path.
0706: * Path information is provided as {@link SVNAdminPath} objects and
0707: * include the following pieces:
0708: * <ul>
0709: * <li>path (use {@link SVNAdminPath#getPath()} to retrieve it)</li>
0710: * <li>tree depth (use {@link SVNAdminPath#getTreeDepth()} to retrieve it)</li>
0711: * <li>node id (optional, use {@link SVNAdminPath#getNodeID()} to retrieve it)</li>
0712: * <li>file/dir information (use {@link SVNAdminPath#isDir()} to retrieve it)</li>
0713: * </ul>
0714: *
0715: * For tree retrieval only these listed <code>get</code> methods of <b>SVNAdminPath</b> are
0716: * relevant.
0717: *
0718: * <p>
0719: * <code>path</code> must be absolute, that is it must start with <code>'/'</code>.
0720: * If <code>path</code> is <span class="javakeyword">null</span> it defaults to
0721: * <code>"/"</code>.
0722: *
0723: * @param repositoryRoot a repository root directory path
0724: * @param path an absolute path
0725: * @param transactionName a transaction name
0726: * @param includeIDs if <span class="javakeyword">true</span> a node
0727: * revision id is also included for each path
0728: * @param handler a tree handler
0729: * @throws SVNException <ul>
0730: * <li>no repository is found at
0731: * <code>repositoryRoot</code>
0732: * </li>
0733: * <li>if <code>path</code> is not found
0734: * </li>
0735: * <li>if the specified transaction is not found
0736: * </li>
0737: * </ul>
0738: */
0739: public void doGetTree(File repositoryRoot, String path,
0740: String transactionName, boolean includeIDs,
0741: ISVNTreeHandler handler) throws SVNException {
0742: FSFS fsfs = open(repositoryRoot, transactionName);
0743: FSTransactionInfo txn = fsfs.openTxn(transactionName);
0744: FSRoot root = fsfs.createTransactionRoot(txn.getTxnId());
0745: path = path == null ? "/" : path;
0746: FSRevisionNode node = root.getRevisionNode(path);
0747: FSID id = includeIDs ? node.getId() : null;
0748: SVNNodeKind kind = root.checkNodeKind(path);
0749: getTree(fsfs, root, path, kind, id, includeIDs, 0, handler);
0750: }
0751:
0752: /**
0753: * Writes differences of changed files and properties for the
0754: * given revision to the provided output stream. If no special diff generator
0755: * {@link #setDiffGenerator(ISVNGNUDiffGenerator) was provided} to
0756: * this client a default GNU-style diff generator is used (which
0757: * writes differences just like the <code>'svnlook diff'</code> command).
0758: *
0759: * <p>
0760: * The provided output stream is not closed within this method.
0761: *
0762: * @param repositoryRoot a repository root directory path
0763: * @param revision a revision number
0764: * @param diffDeleted if <span class="javakeyword">true</span>
0765: * differences for deleted files are included,
0766: * otherwise not
0767: * @param diffAdded if <span class="javakeyword">true</span>
0768: * differences for added files are included,
0769: * otherwise not
0770: * @param diffCopyFrom if <span class="javakeyword">true</span>
0771: * writes differences against the copy source
0772: * (if any), otherwise not
0773: * @param os an output stream to write differences to
0774: * @throws SVNException no repository is found at
0775: * <code>repositoryRoot</code>
0776: */
0777: public void doGetDiff(File repositoryRoot, SVNRevision revision,
0778: boolean diffDeleted, boolean diffAdded,
0779: boolean diffCopyFrom, OutputStream os) throws SVNException {
0780: FSFS fsfs = open(repositoryRoot, revision);
0781: long revNum = SVNAdminHelper.getRevisionNumber(revision, fsfs
0782: .getYoungestRevision(), fsfs);
0783: FSRoot root = fsfs.createRevisionRoot(revNum);
0784: long baseRevision = revNum - 1;
0785: if (!SVNRevision.isValidRevisionNumber(baseRevision)) {
0786: SVNErrorMessage err = SVNErrorMessage.create(
0787: SVNErrorCode.FS_NO_SUCH_REVISION,
0788: "Invalid base revision {0,number,integer}",
0789: new Long(baseRevision));
0790: SVNErrorManager.error(err);
0791: }
0792: SVNNodeEditor editor = generateDeltaTree(fsfs, root,
0793: baseRevision);
0794: ISVNGNUDiffGenerator generator = getDiffGenerator();
0795: generator.setDiffAdded(diffAdded);
0796: generator.setDiffCopied(diffCopyFrom);
0797: generator.setDiffDeleted(diffDeleted);
0798: editor.diff(root, baseRevision, generator, os);
0799: }
0800:
0801: /**
0802: * Writes differences of changed files and properties for the
0803: * given transaction to the provided output stream. If no special diff generator
0804: * {@link #setDiffGenerator(ISVNGNUDiffGenerator) was provided} to
0805: * this client a default GNU-style diff generator is used (which
0806: * writes differences just like the <code>'svnlook diff'</code> command).
0807: *
0808: * @param repositoryRoot a repository root directory path
0809: * @param transactionName a transaction name
0810: * @param diffDeleted if <span class="javakeyword">true</span>
0811: * differences for deleted files are included,
0812: * otherwise not
0813: * @param diffAdded if <span class="javakeyword">true</span>
0814: * differences for added files are included,
0815: * otherwise not
0816: * @param diffCopyFrom if <span class="javakeyword">true</span>
0817: * writes differences against the copy source
0818: * (if any), otherwise not
0819: * @param os an output stream to write differences to
0820: * @throws SVNException <ul>
0821: * <li>no repository is found at
0822: * <code>repositoryRoot</code>
0823: * </li>
0824: * <li>if the specified transaction is not found
0825: * </li>
0826: * </ul>
0827: */
0828: public void doGetDiff(File repositoryRoot, String transactionName,
0829: boolean diffDeleted, boolean diffAdded,
0830: boolean diffCopyFrom, OutputStream os) throws SVNException {
0831: FSFS fsfs = open(repositoryRoot, transactionName);
0832: FSTransactionInfo txn = fsfs.openTxn(transactionName);
0833: FSRoot root = fsfs.createTransactionRoot(txn.getTxnId());
0834: long baseRevision = txn.getBaseRevision();
0835:
0836: if (!SVNRevision.isValidRevisionNumber(baseRevision)) {
0837: SVNErrorMessage err = SVNErrorMessage
0838: .create(
0839: SVNErrorCode.FS_NO_SUCH_REVISION,
0840: "Transaction ''{0}'' is not based on a revision; how odd",
0841: transactionName);
0842: SVNErrorManager.error(err);
0843: }
0844: SVNNodeEditor editor = generateDeltaTree(fsfs, root,
0845: baseRevision);
0846: ISVNGNUDiffGenerator generator = getDiffGenerator();
0847: generator.setDiffAdded(diffAdded);
0848: generator.setDiffCopied(diffCopyFrom);
0849: generator.setDiffDeleted(diffDeleted);
0850: editor.diff(root, baseRevision, generator, os);
0851: }
0852:
0853: /**
0854: * Returns the value of a versioned property for the specified path in the
0855: * given revision.
0856: *
0857: * <p>
0858: * <code>path</code> must be absolute, that is it must start with <code>'/'</code>.
0859: *
0860: * @param repositoryRoot a repository root directory path
0861: * @param propName a property name
0862: * @param path an absolute path
0863: * @param revision a revision number
0864: * @return the value of a property
0865: * @throws SVNException <ul>
0866: * <li>no repository is found at
0867: * <code>repositoryRoot</code>
0868: * </li>
0869: * <li>if <code>path</code> is not found
0870: * </li>
0871: * </ul>
0872: */
0873: public String doGetProperty(File repositoryRoot, String propName,
0874: String path, SVNRevision revision) throws SVNException {
0875: Map props = getProperties(repositoryRoot, propName, path,
0876: revision, null, true, false);
0877: return (String) props.get(propName);
0878: }
0879:
0880: /**
0881: * Returns versioned properties for the specified path in the
0882: * given revision.
0883: *
0884: * <p>
0885: * <code>path</code> must be absolute, that is it must start with <code>'/'</code>.
0886: *
0887: * @param repositoryRoot a repository root directory path
0888: * @param path an absolute path
0889: * @param revision a revision number
0890: * @return name (String) to value (String) mappings
0891: * @throws SVNException <ul>
0892: * <li>no repository is found at
0893: * <code>repositoryRoot</code>
0894: * </li>
0895: * <li>if <code>path</code> is not found
0896: * </li>
0897: * </ul>
0898: */
0899: public Map doGetProperties(File repositoryRoot, String path,
0900: SVNRevision revision) throws SVNException {
0901: return getProperties(repositoryRoot, null, path, revision,
0902: null, false, false);
0903: }
0904:
0905: /**
0906: * Returns the value of a versioned property for the specified path in the
0907: * given transaction.
0908: *
0909: * <p>
0910: * <code>path</code> must be absolute, that is it must start with <code>'/'</code>.
0911: *
0912: * @param repositoryRoot a repository root directory path
0913: * @param propName a property name
0914: * @param path an absolute path
0915: * @param transactionName a transaction name
0916: * @return the value of a property
0917: * @throws SVNException <ul>
0918: * <li>no repository is found at
0919: * <code>repositoryRoot</code>
0920: * </li>
0921: * <li>if <code>path</code> is not found
0922: * </li>
0923: * <li>if the specified transaction is not found
0924: * </li>
0925: * </ul>
0926: */
0927: public String doGetProperty(File repositoryRoot, String propName,
0928: String path, String transactionName) throws SVNException {
0929: Map props = getProperties(repositoryRoot, propName, path, null,
0930: transactionName, true, false);
0931: return (String) props.get(propName);
0932: }
0933:
0934: /**
0935: * Returns versioned properties for the specified path in the
0936: * given transaction.
0937: *
0938: * <p>
0939: * <code>path</code> must be absolute, that is it must start with <code>'/'</code>.
0940: *
0941: * @param repositoryRoot a repository root directory path
0942: * @param path an absolute path
0943: * @param transactionName a transaction name
0944: * @return name (String) to value (String) mappings
0945: * @throws SVNException <ul>
0946: * <li>no repository is found at
0947: * <code>repositoryRoot</code>
0948: * </li>
0949: * <li>if <code>path</code> is not found
0950: * </li>
0951: * <li>if the specified transaction is not found
0952: * </li>
0953: * </ul>
0954: */
0955: public Map doGetProperties(File repositoryRoot, String path,
0956: String transactionName) throws SVNException {
0957: return getProperties(repositoryRoot, null, path, null,
0958: transactionName, false, false);
0959: }
0960:
0961: /**
0962: * Returns the value of a revision property in the given revision.
0963: *
0964: * @param repositoryRoot a repository root directory path
0965: * @param propName a property name
0966: * @param revision a revision number
0967: * @return the value of a revision property
0968: * @throws SVNException no repository is found at
0969: * <code>repositoryRoot</code>
0970: */
0971: public String doGetRevisionProperty(File repositoryRoot,
0972: String propName, SVNRevision revision) throws SVNException {
0973: Map revProps = getProperties(repositoryRoot, propName, null,
0974: revision, null, true, true);
0975: return (String) revProps.get(propName);
0976: }
0977:
0978: /**
0979: * Returns revision properties in the given revision.
0980: *
0981: * @param repositoryRoot a repository root directory path
0982: * @param revision a revision number
0983: * @return name (String) to value (String) mappings
0984: * @throws SVNException no repository is found at
0985: * <code>repositoryRoot</code>
0986: */
0987: public Map doGetRevisionProperties(File repositoryRoot,
0988: SVNRevision revision) throws SVNException {
0989: return getProperties(repositoryRoot, null, null, revision,
0990: null, false, true);
0991: }
0992:
0993: /**
0994: * Returns the value of a revision property for the given transaction.
0995: *
0996: * @param repositoryRoot a repository root directory path
0997: * @param propName a property name
0998: * @param transactionName a transaction name
0999: * @return the value of a revision property
1000: * @throws SVNException <ul>
1001: * <li>no repository is found at
1002: * <code>repositoryRoot</code>
1003: * </li>
1004: * <li>if the specified transaction is not found
1005: * </li>
1006: * </ul>
1007: */
1008: public String doGetRevisionProperty(File repositoryRoot,
1009: String propName, String transactionName)
1010: throws SVNException {
1011: Map revProps = getProperties(repositoryRoot, propName, null,
1012: null, transactionName, true, true);
1013: return (String) revProps.get(propName);
1014: }
1015:
1016: /**
1017: * Returns revision properties for the given transaction.
1018: *
1019: * @param repositoryRoot a repository root directory path
1020: * @param transactionName a transaction name
1021: * @return name (String) to value (String) mappings
1022: * @throws SVNException <ul>
1023: * <li>no repository is found at
1024: * <code>repositoryRoot</code>
1025: * </li>
1026: * <li>if the specified transaction is not found
1027: * </li>
1028: * </ul>
1029: */
1030: public Map doGetRevisionProperties(File repositoryRoot,
1031: String transactionName) throws SVNException {
1032: return getProperties(repositoryRoot, null, null, null,
1033: transactionName, false, true);
1034: }
1035:
1036: /**
1037: * Sets a diff generator to be used in <code>doGetDiff()</code> methods of this class.
1038: *
1039: * @param diffGenerator
1040: * @see #getDiffGenerator()
1041: */
1042: public void setDiffGenerator(ISVNGNUDiffGenerator diffGenerator) {
1043: myDiffGenerator = diffGenerator;
1044: }
1045:
1046: /**
1047: * Returns a diff generator to be used in <code>doGetDiff()</code> methods of this class.
1048: * If no generator was provided by a caller, <b>SVNLookClient</b> uses a default one
1049: * that prints differences in a GNU-style.
1050: *
1051: * @return a diff generator
1052: * @see #setDiffGenerator(ISVNGNUDiffGenerator)
1053: */
1054: public ISVNGNUDiffGenerator getDiffGenerator() {
1055: if (myDiffGenerator == null) {
1056: myDiffGenerator = new DefaultSVNGNUDiffGenerator();
1057: }
1058: return myDiffGenerator;
1059: }
1060:
1061: private void getTree(FSFS fsfs, FSRoot root, String path,
1062: SVNNodeKind kind, FSID id, boolean includeIDs, int depth,
1063: ISVNTreeHandler handler) throws SVNException {
1064: checkCancelled();
1065: if (handler != null) {
1066: handler
1067: .handlePath(new SVNAdminPath(path, includeIDs ? id
1068: .toString() : null, depth,
1069: kind == SVNNodeKind.DIR));
1070: }
1071:
1072: if (kind != SVNNodeKind.DIR) {
1073: return;
1074: }
1075:
1076: FSRevisionNode node = root.getRevisionNode(path);
1077: Map entries = node.getDirEntries(fsfs);
1078: for (Iterator names = entries.keySet().iterator(); names
1079: .hasNext();) {
1080: String name = (String) names.next();
1081: FSEntry entry = (FSEntry) entries.get(name);
1082: getTree(fsfs, root, SVNPathUtil.concatToAbs(path, entry
1083: .getName()), entry.getType(), includeIDs ? entry
1084: .getId() : null, includeIDs, depth + 1, handler);
1085: }
1086: }
1087:
1088: private Map getProperties(File repositoryRoot, String propName,
1089: String path, SVNRevision revision, String txnName,
1090: boolean singleProp, boolean revProps) throws SVNException {
1091: if (propName == null && singleProp) {
1092: SVNErrorMessage err = SVNErrorMessage.create(
1093: SVNErrorCode.CL_INSUFFICIENT_ARGS,
1094: "Missing propname argument");
1095: SVNErrorManager.error(err);
1096: }
1097: if (path == null && !revProps) {
1098: SVNErrorMessage err = SVNErrorMessage.create(
1099: SVNErrorCode.CL_INSUFFICIENT_ARGS,
1100: "Missing repository path argument");
1101: SVNErrorManager.error(err);
1102: }
1103:
1104: FSFS fsfs = txnName == null ? open(repositoryRoot, revision)
1105: : open(repositoryRoot, txnName);
1106: FSRoot root = null;
1107: if (txnName == null) {
1108: long revNum = SVNAdminHelper.getRevisionNumber(revision,
1109: fsfs.getYoungestRevision(), fsfs);
1110: if (revProps) {
1111: return fsfs.getRevisionProperties(revNum);
1112: }
1113: root = fsfs.createRevisionRoot(revNum);
1114: } else {
1115: FSTransactionInfo txn = fsfs.openTxn(txnName);
1116: if (revProps) {
1117: return fsfs.getTransactionProperties(txn.getTxnId());
1118: }
1119: root = fsfs.createTransactionRoot(txn.getTxnId());
1120: }
1121:
1122: verifyPath(root, path);
1123: FSRevisionNode node = root.getRevisionNode(path);
1124: return node.getProperties(fsfs);
1125: }
1126:
1127: private void getHistory(FSFS fsfs, String path, long start,
1128: long end, boolean crossCopies, boolean includeIDs,
1129: ISVNHistoryHandler handler) throws SVNException {
1130: if (!SVNRevision.isValidRevisionNumber(start)) {
1131: SVNErrorMessage err = SVNErrorMessage.create(
1132: SVNErrorCode.FS_NO_SUCH_REVISION,
1133: "Invalid start revision {0,number,integer}",
1134: new Long(start));
1135: SVNErrorManager.error(err);
1136: }
1137: if (!SVNRevision.isValidRevisionNumber(end)) {
1138: SVNErrorMessage err = SVNErrorMessage.create(
1139: SVNErrorCode.FS_NO_SUCH_REVISION,
1140: "Invalid end revision {0,number,integer}",
1141: new Long(end));
1142: SVNErrorManager.error(err);
1143: }
1144:
1145: if (start > end) {
1146: long tmpRev = start;
1147: start = end;
1148: end = tmpRev;
1149: }
1150:
1151: FSRevisionRoot root = fsfs.createRevisionRoot(end);
1152: FSNodeHistory history = FSNodeHistory
1153: .getNodeHistory(root, path);
1154:
1155: do {
1156: history = history.fsHistoryPrev(crossCopies, fsfs);
1157: if (history == null) {
1158: break;
1159: }
1160:
1161: long revision = history.getHistoryEntry().getRevision();
1162: if (revision < start) {
1163: break;
1164: }
1165:
1166: String id = null;
1167: if (includeIDs) {
1168: FSRevisionRoot revRoot = fsfs
1169: .createRevisionRoot(revision);
1170: FSRevisionNode node = revRoot.getRevisionNode(history
1171: .getHistoryEntry().getPath());
1172: id = node.getId().toString();
1173: }
1174:
1175: if (handler != null) {
1176: handler.handlePath(new SVNAdminPath(history
1177: .getHistoryEntry().getPath(), id, revision));
1178: }
1179: } while (history != null);
1180:
1181: }
1182:
1183: private SVNNodeEditor generateDeltaTree(FSFS fsfs, FSRoot root,
1184: long baseRevision) throws SVNException {
1185: FSRevisionRoot baseRoot = fsfs.createRevisionRoot(baseRevision);
1186: SVNNodeEditor editor = new SVNNodeEditor(fsfs, baseRoot, this );
1187: FSRepositoryUtil.replay(fsfs, root, "", -1, false, editor);
1188: return editor;
1189: }
1190:
1191: private void catFile(FSRoot root, String path, OutputStream out)
1192: throws SVNException {
1193: SVNNodeKind kind = verifyPath(root, path);
1194: if (kind != SVNNodeKind.FILE) {
1195: SVNErrorMessage err = SVNErrorMessage.create(
1196: SVNErrorCode.FS_NOT_FILE,
1197: "Path ''{0}'' is not a file", path);
1198: SVNErrorManager.error(err);
1199: }
1200:
1201: if (out != null) {
1202: InputStream contents = null;
1203: try {
1204: contents = root.getFileStreamForPath(
1205: new SVNDeltaCombiner(), path);
1206: byte[] buffer = new byte[SVNAdminHelper.STREAM_CHUNK_SIZE];
1207: int len = 0;
1208: do {
1209: checkCancelled();
1210: len = contents.read(buffer);
1211: out.write(buffer, 0, len);
1212: } while (len == SVNAdminHelper.STREAM_CHUNK_SIZE);
1213: } catch (IOException ioe) {
1214: SVNErrorMessage err = SVNErrorMessage.create(
1215: SVNErrorCode.IO_ERROR, ioe
1216: .getLocalizedMessage());
1217: SVNErrorManager.error(err, ioe);
1218: } finally {
1219: SVNFileUtil.closeFile(contents);
1220: }
1221: }
1222: }
1223:
1224: private SVNNodeKind verifyPath(FSRoot root, String path)
1225: throws SVNException {
1226: SVNNodeKind kind = root.checkNodeKind(path);
1227: if (kind == SVNNodeKind.NONE) {
1228: SVNErrorMessage err = SVNErrorMessage.create(
1229: SVNErrorCode.FS_NOT_FOUND,
1230: "Path ''{0}'' does not exist", path);
1231: SVNErrorManager.error(err);
1232: }
1233: return kind;
1234: }
1235:
1236: private FSFS open(File repositoryRoot, SVNRevision revision)
1237: throws SVNException {
1238: if (revision == null || !revision.isValid()) {
1239: SVNErrorMessage err = SVNErrorMessage.create(
1240: SVNErrorCode.CL_ARG_PARSING_ERROR,
1241: "Invalid revision number supplied");
1242: SVNErrorManager.error(err);
1243: }
1244:
1245: FSFS fsfs = SVNAdminHelper.openRepository(repositoryRoot);
1246: return fsfs;
1247: }
1248:
1249: private FSFS open(File repositoryRoot, String transactionName)
1250: throws SVNException {
1251: if (transactionName == null) {
1252: SVNErrorMessage err = SVNErrorMessage.create(
1253: SVNErrorCode.CL_INSUFFICIENT_ARGS,
1254: "Missing transaction name");
1255: SVNErrorManager.error(err);
1256: }
1257:
1258: return SVNAdminHelper.openRepository(repositoryRoot);
1259: }
1260: }
|