package org.tmatesoft.svn.core.internal.wc16; import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.TreeMap; import java.util.logging.Level; import org.tmatesoft.svn.core.ISVNLogEntryHandler; import org.tmatesoft.svn.core.SVNDepth; import org.tmatesoft.svn.core.SVNErrorCode; import org.tmatesoft.svn.core.SVNErrorMessage; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNMergeRange; import org.tmatesoft.svn.core.SVNMergeRangeList; import org.tmatesoft.svn.core.SVNNodeKind; import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager; import org.tmatesoft.svn.core.internal.util.SVNMergeInfoUtil; import org.tmatesoft.svn.core.internal.util.SVNPathUtil; import org.tmatesoft.svn.core.internal.wc.AbstractDiffCallback; import org.tmatesoft.svn.core.internal.wc.SVNAmbientDepthFilterEditor; import org.tmatesoft.svn.core.internal.wc.SVNCancellableEditor; import org.tmatesoft.svn.core.internal.wc.SVNDiffCallback; import org.tmatesoft.svn.core.internal.wc.SVNDiffEditor; import org.tmatesoft.svn.core.internal.wc.SVNDiffStatusEditor; import org.tmatesoft.svn.core.internal.wc.SVNErrorManager; import org.tmatesoft.svn.core.internal.wc.SVNEventFactory; import org.tmatesoft.svn.core.internal.wc.SVNFileUtil; import org.tmatesoft.svn.core.internal.wc.SVNMergeDriver; import org.tmatesoft.svn.core.internal.wc.SVNRemoteDiffEditor; import org.tmatesoft.svn.core.internal.wc.admin.SVNAdminArea; import org.tmatesoft.svn.core.internal.wc.admin.SVNAdminAreaInfo; import org.tmatesoft.svn.core.internal.wc.admin.SVNEntry; import org.tmatesoft.svn.core.internal.wc.admin.SVNReporter; import org.tmatesoft.svn.core.internal.wc.admin.SVNWCAccess; import org.tmatesoft.svn.core.internal.wc.patch.SVNPatch; import org.tmatesoft.svn.core.internal.wc.patch.SVNPatchFileStream; import org.tmatesoft.svn.core.internal.wc.patch.SVNPatchTarget; import org.tmatesoft.svn.core.io.ISVNEditor; import org.tmatesoft.svn.core.io.ISVNReporter; import org.tmatesoft.svn.core.io.ISVNReporterBaton; import org.tmatesoft.svn.core.io.SVNCapability; import org.tmatesoft.svn.core.io.SVNLocationEntry; import org.tmatesoft.svn.core.io.SVNRepository; import org.tmatesoft.svn.core.wc.DefaultSVNDiffGenerator; import org.tmatesoft.svn.core.wc.ISVNDiffGenerator; import org.tmatesoft.svn.core.wc.ISVNDiffStatusHandler; import org.tmatesoft.svn.core.wc.ISVNEventHandler; import org.tmatesoft.svn.core.wc.ISVNOptions; import org.tmatesoft.svn.core.wc.ISVNRepositoryPool; import org.tmatesoft.svn.core.wc.SVNDiffOptions; import org.tmatesoft.svn.core.wc.SVNDiffStatus; import org.tmatesoft.svn.core.wc.SVNLogClient; import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc.SVNRevisionRange; import org.tmatesoft.svn.core.wc.SVNStatusType; import org.tmatesoft.svn.core.wc.SVNWCUtil; import org.tmatesoft.svn.util.SVNLogType; /** * The <b>SVNDiffClient</b> class provides methods allowing to get differences * between versioned items ('diff' operation) as well as ones intended for * merging file contents. * <p> * Here's a list of the <b>SVNDiffClient</b>'s methods matched against * corresponing commands of the SVN command line client: * <table cellpadding="3" cellspacing="1" border="0" width="40%" bgcolor="#999933"> * <tr bgcolor="#ADB8D9" align="left"> * <td><b>SVNKit</b></td> * <td><b>Subversion</b></td> * </tr> * <tr bgcolor="#EAEAEA" align="left"> * <td>doDiff()</td> * <td>'svn diff'</td> * </tr> * <tr bgcolor="#EAEAEA" align="left"> * <td>doDiffStatus()</td> * <td>'svn diff --summarize'</td> * </tr> * <tr bgcolor="#EAEAEA" align="left"> * <td>doMerge()</td> * <td>'svn merge'</td> * </tr> * <tr bgcolor="#EAEAEA" align="left"> * <td>doGetLogXXXMergeInfo()</td> * <td>'svn mergeinfo'</td> * </tr> * </table> * * @version 1.3 * @since 1.2 * @author TMate Software Ltd. */ public class SVNDiffClient16 extends SVNMergeDriver { private ISVNDiffGenerator myDiffGenerator; private SVNDiffOptions myDiffOptions; /** * Constructs and initializes an <b>SVNDiffClient</b> object with the * specified run-time configuration and authentication drivers. * <p/> * If <code>options</code> is <span class="javakeyword">null</span>, then * this <b>SVNDiffClient</b> will be using a default run-time configuration * driver which takes client-side settings from the default SVN's run-time * configuration area but is not able to change those settings (read more on * {@link ISVNOptions} and {@link SVNWCUtil}). * <p/> * If <code>authManager</code> is <span class="javakeyword">null</span>, * then this <b>SVNDiffClient</b> will be using a default authentication and * network layers driver (see * {@link SVNWCUtil#createDefaultAuthenticationManager()}) which uses * server-side settings and auth storage from the default SVN's run-time * configuration area (or system properties if that area is not found). * * @param authManageran * authentication and network layers driver * @param optionsa * run-time configuration options driver */ public SVNDiffClient16(ISVNAuthenticationManager authManager, ISVNOptions options) { super(authManager, options); } /** * Constructs and initializes an <b>SVNDiffClient</b> object with the * specified run-time configuration and repository pool object. * <p/> * If <code>options</code> is <span class="javakeyword">null</span>, then * this <b>SVNDiffClient</b> will be using a default run-time configuration * driver which takes client-side settings from the default SVN's run-time * configuration area but is not able to change those settings (read more on * {@link ISVNOptions} and {@link SVNWCUtil}). * <p/> * If <code>repositoryPool</code> is <span class="javakeyword">null</span>, * then {@link org.tmatesoft.svn.core.io.SVNRepositoryFactory} will be used * to create {@link SVNRepository repository access objects}. * * @param repositoryPoola * repository pool object * @param optionsa * run-time configuration options driver */ public SVNDiffClient16(ISVNRepositoryPool repositoryPool, ISVNOptions options) { super(repositoryPool, options); } /** * Sets the specified diff driver for this object to use for generating and * writing file differences to an otput stream. * <p> * If no specific diff driver was set in this way, a default one will be * used (see {@link DefaultSVNDiffGenerator}). * * @param diffGeneratora * diff driver * @see #getDiffGenerator() */ public void setDiffGenerator(ISVNDiffGenerator diffGenerator) { this.myDiffGenerator = diffGenerator; } /** * Returns the diff driver being in use. * <p> * If no specific diff driver was previously provided, a default one will be * returned (see {@link DefaultSVNDiffGenerator}). * * @return the diff driver being in use * @see #setDiffGenerator(ISVNDiffGenerator) */ public ISVNDiffGenerator getDiffGenerator() { return this.myDiffGenerator; } /** * Sets diff options for this client to use in merge operations. * * @param diffOptionsdiff * options object */ public void setMergeOptions(SVNDiffOptions diffOptions) { myDiffOptions = diffOptions; } /** * Gets the diff options that are used in merge operations by this client. * If none was provided by the user, one created as * <code>new SVNDiffOptions()</code> will be returned and used further. * * @return diff options */ public SVNDiffOptions getMergeOptions() { if (myDiffOptions == null) { myDiffOptions = new SVNDiffOptions(); } return myDiffOptions; } /** * Generates the differences for the specified URL taken from the two * specified revisions and writes the result to the provided output stream. * <p> * Corresponds to the SVN command line client's <code>'svn diff -r N:M URL'</code> command. * * @param urla * repository location * @param pegRevision a * revision in which <code>url</code> is first looked up * @param rNan * old revision * @param rMa * new revision * @param recursive * <span class="javakeyword">true</span> to descend recursively * @param useAncestry if * <span class="javakeyword">true</span> then the paths ancestry * will be noticed while calculating differences, otherwise not * @param result the * target {@link java.io.OutputStream} where the differences will * be written to * @throws SVNException if * one of the following is true: * <ul> * <li>at least one of <code>rN</code>, <code>rM</code> and * <code>pegRevision</code> is invalid <li>at least one of * <code>rN</code> and <code>rM</code> is a local revision (see * {@link SVNRevision#isLocal()}) <li><code>url</code> was not * found in <code>rN</code> <li><code>url</code> was not found * in <code>rM</code> * </ul> * @deprecated use * {@link #doDiff(SVNURL,SVNRevision,SVNRevision,SVNRevision,SVNDepth,boolean,OutputStream)} * instead */ public void doDiff(SVNURL url, SVNRevision pegRevision, SVNRevision rN, SVNRevision rM, boolean recursive, boolean useAncestry, OutputStream result) throws SVNException { doDiff(url, pegRevision, rN, rM, SVNDepth.getInfinityOrFilesDepth(recursive), useAncestry, result); } /** * Produces diff output which describes the delta between <code>url</code> * in peg revision <code>pegRevision</code>, as it changed between * <code>rN</code> and <code>rM</code>. * <p/> * If * * <code>pegRevision is {@link SVNRevision#isValid() invalid}, behaves identically to {@link #doDiff(SVNURL,SVNRevision,SVNURL,SVNRevision,SVNDepth,boolean,OutputStream)}, * using <code>url</code> for both of that function's <code>url1</code> and * <code>url2</code> arguments. * <p/> * All other options are handled identically to * {@link #doDiff(SVNURL,SVNRevision,SVNURL,SVNRevision,SVNDepth,boolean,OutputStream)}. * * @param urla * repository location * @param pegRevision a * revision in which <code>url</code> is first looked up * @param rNan * old revision * @param rMa * new revision * @param depth tree * depth to process * @param useAncestry if * <span class="javakeyword">true</span> then the paths ancestry * will be noticed while calculating differences, otherwise not * @param result the * target {@link java.io.OutputStream} where the differences will * be written to * @throws SVNException if * one of the following is true: * <ul> * <li>exception with {@link SVNErrorCode#CLIENT_BAD_REVISION} * error code - if either of <code>rN</code> and <code>rM</code> * is either {@link SVNRevision#isValid() invalid} or * {@link SVNRevision#isLocal() local} <li>exception with * {@link SVNErrorCode#FS_NOT_FOUND} error code - <code>url * </code> can not be found in either <code>rN</code> or <code> * rM</code> * </ul> * @since 1.2, SVN 1.5 */ public void doDiff(SVNURL url, SVNRevision pegRevision, SVNRevision rN, SVNRevision rM, SVNDepth depth, boolean useAncestry, OutputStream result) throws SVNException { if (!rN.isValid() || !rM.isValid()) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.CLIENT_BAD_REVISION, "Both rN and rM revisions should be specified"); SVNErrorManager.error(err, SVNLogType.DEFAULT); } if (rN.isLocal() || rM.isLocal()) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.CLIENT_BAD_REVISION, "Both rN and rM revisions must be non-local for a pegged diff of an URL"); SVNErrorManager.error(err, SVNLogType.DEFAULT); } getDiffGenerator().init(url.toString(), url.toString()); doDiffURLURL(url, null, rN, url, null, rM, pegRevision, depth, useAncestry, result); } /** * Generates the differences for the specified path taken from the two * specified revisions and writes the result to the provided output stream. * <p> * If <code>rM</code> is a local revision (see {@link SVNRevision#isLocal()} * ), then the Working Copy <code>path</code> is compared with the * corresponding repository file at revision <code>rN</code> (that is * similar to the SVN command line client's <code>'svn diff -r N path'</code> command). * <p> * Otherwise if both <code>rN</code> and <code>rM</code> are non-local, then * the repository location of <code>path</code> is compared for these * revisions (<code>'svn diff -r N:M URL'</code>). * * @param patha * Working Copy path * @param pegRevision a * revision in which the repository location of <code>path</code> * is first looked up * @param rNan * old revision * @param rMa * new revision (or a local one) * @param recursive * <span class="javakeyword">true</span> to descend recursively * @param useAncestry if * <span class="javakeyword">true</span> then the paths ancestry * will be noticed while calculating differences, otherwise not * @param result the * target {@link java.io.OutputStream} where the differences will * be written to * @throws SVNException if * one of the following is true: * <ul> * <li>at least one of <code>rN</code>, <code>rM</code> and * <code>pegRevision</code> is invalid <li>both <code>rN</code> * and <code>rM</code> are local revisions <li><code>path</code> * was not found in <code>rN</code> <li><code>path</code> was * not found in <code>rM</code> * </ul> * @deprecated use * {@link #doDiff(File,SVNRevision,SVNRevision,SVNRevision,SVNDepth,boolean,OutputStream,Collection)} * instead */ public void doDiff(File path, SVNRevision pegRevision, SVNRevision rN, SVNRevision rM, boolean recursive, boolean useAncestry, OutputStream result) throws SVNException { doDiff(path, pegRevision, rN, rM, SVNDepth.getInfinityOrFilesDepth(recursive), useAncestry, result, null); } /** * Iterates over the passed in <code>paths</code> calling * {@link #doDiff(File,SVNRevision,SVNRevision,SVNRevision,SVNDepth,boolean,OutputStream,Collection)} * for each one in the array. * * @param pathsarray * of working copy paths * @param rNan * old revision * @param rMa * new revision * @param pegRevision a * revision in which the repository location of * <code>paths</code> is first looked up * @param depth tree * depth to process * @param useAncestry if * <span class="javakeyword">true</span> then the paths ancestry * will be noticed while calculating differences, otherwise not * @param result the * target {@link java.io.OutputStream} where the differences will * be written to * @param changeLists collection * with changelist names * @throws SVNException * @since 1.2, SVN 1.5 */ public void doDiff(File[] paths, SVNRevision rN, SVNRevision rM, SVNRevision pegRevision, SVNDepth depth, boolean useAncestry, OutputStream result, Collection changeLists) throws SVNException { if (paths == null) { return; } for (int i = 0; i < paths.length; i++) { File path = paths[i]; try { doDiff(path, pegRevision, rN, rM, depth, useAncestry, result, changeLists); } catch (SVNException svne) { dispatchEvent(SVNEventFactory.createErrorEvent(svne.getErrorMessage(), null)); } } } /** * Produces diff output which describes the delta between <code>path</code> * in peg revision <code>pegRevision</code>, as it changed between * <code>rN</code> and <code>rM</code>. * <p/> * If <code>rM</code> is neither {@link SVNRevision#BASE}, nor * {@link SVNRevision#WORKING}, nor {@link SVNRevision#COMMITTED}, and if, * on the contrary, <code>rN</code> is one of the aforementioned revisions, * then a wc-against-url diff is performed; if <code>rN</code> also is not * one of those revision constants, then a url-against-url diff is * performed. Otherwise it's a url-against-wc diff. * <p/> * If * * <code>pegRevision is {@link SVNRevision#isValid() invalid}, behaves identically to {@link #doDiff(File,SVNRevision,File,SVNRevision,SVNDepth,boolean,OutputStream,Collection)}, * using <code>path</code> for both of that function's <code>path1</code> * and <code>path2</code> arguments. * <p/> * All other options are handled identically to * {@link #doDiff(File,SVNRevision,File,SVNRevision,SVNDepth,boolean,OutputStream,Collection)}. * * @param patha * Working Copy path * @param pegRevision a * revision in which the repository location of <code>path</code> * is first looked up * @param rNan * old revision * @param rMa * new revision * @param depth tree * depth to process * @param useAncestry if * <span class="javakeyword">true</span> then the paths ancestry * will be noticed while calculating differences, otherwise not * @param result the * target {@link java.io.OutputStream} where the differences will * be written to * @param changeLists collection * with changelist names * @throws SVNException if * one of the following is true: * <ul> * <li>exception with {@link SVNErrorCode#CLIENT_BAD_REVISION} * error code - if either of <code>rN</code> and <code>rM</code> * is {@link SVNRevision#isValid() invalid}; if both <code>rN * </code> and <code>rM</code> are either * {@link SVNRevision#WORKING} or {@link SVNRevision#BASE} <li> * exception with {@link SVNErrorCode#FS_NOT_FOUND} error code - * <code>path</code> can not be found in either <code>rN</code> * or <code>rM</code> * </ul> * @since 1.2, SVN 1.5 */ public void doDiff(File path, SVNRevision pegRevision, SVNRevision rN, SVNRevision rM, SVNDepth depth, boolean useAncestry, OutputStream result, Collection changeLists) throws SVNException { if (!rN.isValid() || !rM.isValid()) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.CLIENT_BAD_REVISION, "Both rN and rM revisions should be specified"); SVNErrorManager.error(err, SVNLogType.DEFAULT); } boolean rNisLocal = rN == SVNRevision.BASE || rN == SVNRevision.WORKING; boolean rMisLocal = rM == SVNRevision.BASE || rM == SVNRevision.WORKING; if (rNisLocal && rMisLocal) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.CLIENT_BAD_REVISION, "At least one revision must be non-local for a pegged diff"); SVNErrorManager.error(err, SVNLogType.DEFAULT); } path = path.getAbsoluteFile(); getDiffGenerator().init(path.getAbsolutePath(), path.getAbsolutePath()); if (!(rM == SVNRevision.BASE || rM == SVNRevision.WORKING || rM == SVNRevision.COMMITTED)) { if ((rN == SVNRevision.BASE || rN == SVNRevision.WORKING || rN == SVNRevision.COMMITTED)) { doDiffURLWC(path, rM, pegRevision, path, rN, true, depth, useAncestry, result, changeLists); } else { doDiffURLURL(null, path, rN, null, path, rM, pegRevision, depth, useAncestry, result); } } else { doDiffURLWC(path, rN, pegRevision, path, rM, false, depth, useAncestry, result, changeLists); } } /** * Generates the differences for the specified URLs taken from the two * specified revisions and writes the result to the provided output stream. * <p> * Corresponds to the SVN command line client's <code>'svn diff -r N:M URL1 URL2'</code> command. * * @param url1 the * first URL to be compared * @param rNa * revision of <code>url1</code> * @param url2 the * second URL to be compared * @param rMa * revision of <code>url2</code> * @param recursive * <span class="javakeyword">true</span> to descend recursively * @param useAncestry if * <span class="javakeyword">true</span> then the paths ancestry * will be noticed while calculating differences, otherwise not * @param result the * target {@link java.io.OutputStream} where the differences will * be written to * @throws SVNException if * one of the following is true: * <ul> * <li>at least one of <code>rN</code> and <code>rM</code> is * invalid <li><code>url1</code> was not found in <code>rN * </code> <li><code>url2</code> was not found in <code>rM * </code> * </ul> * @deprecated use * {@link #doDiff(SVNURL,SVNRevision,SVNURL,SVNRevision,SVNDepth,boolean,OutputStream)} * instead */ public void doDiff(SVNURL url1, SVNRevision rN, SVNURL url2, SVNRevision rM, boolean recursive, boolean useAncestry, OutputStream result) throws SVNException { doDiff(url1, rN, url2, rM, SVNDepth.getInfinityOrFilesDepth(recursive), useAncestry, result); } /** * Produces diff output which describes the delta between <code>url1</code>/ * <code>rN</code> and <code>url2</code>/<code>rM</code>. Writes the output * of the diff to <code>result</code>. * <p/> * If this client object uses {@link DefaultSVNDiffGenerator} and there was * a non-<span class="javakeyword">null</span> * {@link DefaultSVNDiffGenerator#setBasePath(File) base path} provided to * it, the original path and modified path will have this base path stripped * from the front of the respective paths. If the base path is not <span * class="javakeyword">null</span> but is not a parent path of the target, * an exception with the {@link SVNErrorCode#BAD_RELATIVE_PATH} error code * is thrown. * <p/> * <code>url1</code> and <code>url2</code> must both represent the same node * kind -- that is, if <code>url1</code> is a directory, <code>url2</code> * must also be, and if <code>url1</code> is a file, <code>url2</code> must * also be. * <p/> * If <code>depth</code> is {@link SVNDepth#INFINITY}, diffs fully * recursively. Else if it is {@link SVNDepth#IMMEDIATES}, diffs the named * paths and their file children (if any), and diffs properties of * subdirectories, but does not descend further into the subdirectories. * Else if {@link SVNDepth#FILES}, behaves as if for * {@link SVNDepth#IMMEDIATES} except doesn't diff properties of * subdirectories. If {@link SVNDepth#EMPTY}, diffs exactly the named paths * but nothing underneath them. * <p/> * <code>useAncestry</code> controls whether or not items being diffed will * be checked for relatedness first. Unrelated items are typically * transmitted to the editor as a deletion of one thing and the addition of * another, but if this flag is <span class="javakeyword">true</span>, * unrelated items will be diffed as if they were related. * <p/> * If {@link ISVNDiffGenerator#isDiffDeleted()} returns <span * class="javakeyword">true</span>, then no diff output will be generated on * deleted files. * <p/> * Generated headers are encoded using * {@link ISVNDiffGenerator#getEncoding()}. * <p/> * Diffs output will not be generated for binary files, unless * {@link ISVNDiffGenerator#isForcedBinaryDiff()} is <span * class="javakeyword">true</span>, in which case diffs will be shown * regardless of the content types. * <p/> * If this client object uses {@link DefaultSVNDiffGenerator} then a caller * can set {@link SVNDiffOptions} to it which will be used to pass * additional options to the diff processes invoked to compare files. * * @param url1 the * first URL to be compared * @param rNa * revision of <code>url1</code> * @param url2 the * second URL to be compared against <code>path1</code> * @param rMa * revision of <code>url2</code> * @param depth tree * depth to process * @param useAncestry if * <span class="javakeyword">true</span> then the paths ancestry * will be noticed while calculating differences, otherwise not * @param result the * target {@link java.io.OutputStream} where the differences will * be written to * @throws SVNException in * the following cases: * <ul> * <li/>exception with {@link SVNErrorCode#CLIENT_BAD_REVISION} * error code - if either <code>rN</code> or <code>rM</code> is * {@link SVNRevision#isValid() invalid} * </ul> * @since 1.2, SVN 1.5 */ public void doDiff(SVNURL url1, SVNRevision rN, SVNURL url2, SVNRevision rM, SVNDepth depth, boolean useAncestry, OutputStream result) throws SVNException { if (!rN.isValid() || !rM.isValid()) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.CLIENT_BAD_REVISION, "Both rN and rM revisions should be specified"); SVNErrorManager.error(err, SVNLogType.DEFAULT); } getDiffGenerator().init(url1.toString(), url2.toString()); doDiffURLURL(url1, null, rN, url2, null, rM, SVNRevision.UNDEFINED, depth, useAncestry, result); } /** * Generates the differences comparing the specified URL in a certain * revision against either the specified Working Copy path or its repository * location URL in the specified revision, and writes the result to the * provided output stream. * <p> * If <code>rN</code> is not a local revision (see * {@link SVNRevision#isLocal()}), then its repository location URL as it is * in the revision represented by <code>rN</code> is taken for comparison * with <code>url2</code>. * <p> * Corresponds to the SVN command line client's <code>'svn diff -r N:M PATH URL'</code> command. * * @param path1 a * WC path * @param rNa * revision of <code>path1</code> * @param url2a * repository location URL that is to be compared against * <code>path1</code> (or its repository location) * @param rMa * revision of <code>url2</code> * @param recursive * <span class="javakeyword">true</span> to descend recursively * @param useAncestry if * <span class="javakeyword">true</span> then the paths ancestry * will be noticed while calculating differences, otherwise not * @param result the * target {@link java.io.OutputStream} where the differences will * be written to * @throws SVNException if * one of the following is true: * <ul> * <li>at least one of <code>rN</code> and <code>rM</code> is * invalid <li><code>path1</code> is not under version control * <li><code>path1</code> has no URL <li><code>url2</code> was * not found in <code>rM</code> <li>the repository location of * <code>path1</code> was not found in <code>rN</code> * </ul> * @deprecated use * {@link #doDiff(File,SVNRevision,SVNURL,SVNRevision,SVNDepth,boolean,OutputStream,Collection)} * instead */ public void doDiff(File path1, SVNRevision rN, SVNURL url2, SVNRevision rM, boolean recursive, boolean useAncestry, OutputStream result) throws SVNException { doDiff(path1, rN, url2, rM, SVNDepth.getInfinityOrFilesDepth(recursive), useAncestry, result, null); } /** * Produces diff output which describes the delta between <code>path1</code> * /<code>rN</code> and <code>url2</code>/<code>rM</code>. Writes the output * of the diff to <code>result</code>. * <p/> * If this client object uses {@link DefaultSVNDiffGenerator} and there was * a non-<span class="javakeyword">null</span> * {@link DefaultSVNDiffGenerator#setBasePath(File) base path} provided to * it, the original path and modified path will have this base path stripped * from the front of the respective paths. If the base path is not <span * class="javakeyword">null</span> but is not a parent path of the target, * an exception with the {@link SVNErrorCode#BAD_RELATIVE_PATH} error code * is thrown. * <p/> * <code>path1</code> and <code>url2</code> must both represent the same * node kind -- that is, if <code>path1</code> is a directory, * <code>url2</code> must also be, and if <code>path1</code> is a file, * <code>url2</code> must also be. * <p/> * If <code>depth</code> is {@link SVNDepth#INFINITY}, diffs fully * recursively. Else if it is {@link SVNDepth#IMMEDIATES}, diffs the named * paths and their file children (if any), and diffs properties of * subdirectories, but does not descend further into the subdirectories. * Else if {@link SVNDepth#FILES}, behaves as if for * {@link SVNDepth#IMMEDIATES} except doesn't diff properties of * subdirectories. If {@link SVNDepth#EMPTY}, diffs exactly the named paths * but nothing underneath them. * <p/> * <code>useAncestry</code> controls whether or not items being diffed will * be checked for relatedness first. Unrelated items are typically * transmitted to the editor as a deletion of one thing and the addition of * another, but if this flag is <span class="javakeyword">true</span>, * unrelated items will be diffed as if they were related. * <p/> * If {@link ISVNDiffGenerator#isDiffDeleted()} returns <span * class="javakeyword">true</span>, then no diff output will be generated on * deleted files. * <p/> * Generated headers are encoded using * {@link ISVNDiffGenerator#getEncoding()}. * <p/> * Diffs output will not be generated for binary files, unless * {@link ISVNDiffGenerator#isForcedBinaryDiff()} is <span * class="javakeyword">true</span>, in which case diffs will be shown * regardless of the content types. * <p/> * If this client object uses {@link DefaultSVNDiffGenerator} then a caller * can set {@link SVNDiffOptions} to it which will be used to pass * additional options to the diff processes invoked to compare files. * <p/> * <code>changeLists</code> is a collection of <code>String</code> * changelist names, used as a restrictive filter on items whose differences * are reported; that is, doesn't generate diffs about any item unless it's * a member of one of those changelists. If <code>changeLists</code> is * empty (or <span class="javakeyword">null</span>), no changelist filtering * occurs. * <p/> * Note: changelist filtering only applies to diffs in which at least one * side of the diff represents working copy data. * <p/> * If both <code>rN</code> is either {@link SVNRevision#WORKING} or * {@link SVNRevision#BASE}, then it will be a wc-against-url; otherwise, a * url-against-url diff. * * @param path1 a * WC path * @param rNa * revision of <code>path1</code> * @param url2a * repository location URL that is to be compared against * <code>path1</code> (or its repository location) * @param rMa * revision of <code>url2</code> * @param depth tree * depth to process * @param useAncestry if * <span class="javakeyword">true</span> then the paths ancestry * will be noticed while calculating differences, otherwise not * @param result the * target {@link java.io.OutputStream} where the differences will * be written to * @param changeLists collection * with changelist names * @throws SVNException in * the following cases: * <ul> * <li/>exception with {@link SVNErrorCode#CLIENT_BAD_REVISION} * error code - if either <code>rN</code> or <code>rM</code> is * {@link SVNRevision#isValid() invalid} * </ul> * @since 1.2, SVN 1.5 */ public void doDiff(File path1, SVNRevision rN, SVNURL url2, SVNRevision rM, SVNDepth depth, boolean useAncestry, OutputStream result, Collection changeLists) throws SVNException { if (!rN.isValid() || !rM.isValid()) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.CLIENT_BAD_REVISION, "Both rN and rM revisions should be specified"); SVNErrorManager.error(err, SVNLogType.DEFAULT); } getDiffGenerator().init(path1.getAbsolutePath(), url2.toString()); if (rN == SVNRevision.BASE || rN == SVNRevision.WORKING) { doDiffURLWC(url2, rM, SVNRevision.UNDEFINED, path1, rN, true, depth, useAncestry, result, changeLists); } else { doDiffURLURL(null, path1, rN, url2, null, rM, SVNRevision.UNDEFINED, depth, useAncestry, result); } } /** * Generates the differences comparing either the specified Working Copy * path or its repository location URL in the specified revision against the * specified URL in a certain revision, and writes the result to the * provided output stream. * <p> * If <code>rM</code> is not a local revision (see * {@link SVNRevision#isLocal()}), then its repository location URL as it is * in the revision represented by <code>rM</code> is taken for comparison * with <code>url1</code>. * <p> * Corresponds to the SVN command line client's <code>'svn diff -r N:M URL PATH'</code> command. * * @param url1 a * repository location URL * @param rNa * revision of <code>url1</code> * @param path2 a * WC path that is to be compared against <code>url1</code> * @param rMa * revision of <code>path2</code> * @param recursive * <span class="javakeyword">true</span> to descend recursively * @param useAncestry if * <span class="javakeyword">true</span> then the paths ancestry * will be noticed while calculating differences, otherwise not * @param result the * target {@link java.io.OutputStream} where the differences will * be written to * @throws SVNException if * one of the following is true: * <ul> * <li>at least one of <code>rN</code> and <code>rM</code> is * invalid <li><code>path2</code> is not under version control * <li><code>path2</code> has no URL <li><code>url1</code> was * not found in <code>rN</code> <li>the repository location of * <code>path2</code> was not found in <code>rM</code> * </ul> * @deprecated use * {@link #doDiff(SVNURL,SVNRevision,File,SVNRevision,SVNDepth,boolean,OutputStream,Collection)} * instead */ public void doDiff(SVNURL url1, SVNRevision rN, File path2, SVNRevision rM, boolean recursive, boolean useAncestry, OutputStream result) throws SVNException { doDiff(url1, rN, path2, rM, SVNDepth.getInfinityOrFilesDepth(recursive), useAncestry, result, null); } /** * Produces diff output which describes the delta between <code>url1</code>/ * <code>rN</code> and <code>path2</code>/<code>rM</code>. Writes the output * of the diff to <code>result</code>. * <p/> * If this client object uses {@link DefaultSVNDiffGenerator} and there was * a non-<span class="javakeyword">null</span> * {@link DefaultSVNDiffGenerator#setBasePath(File) base path} provided to * it, the original path and modified path will have this base path stripped * from the front of the respective paths. If the base path is not <span * class="javakeyword">null</span> but is not a parent path of the target, * an exception with the {@link SVNErrorCode#BAD_RELATIVE_PATH} error code * is thrown. * <p/> * <code>url1</code> and <code>path2</code> must both represent the same * node kind -- that is, if <code>url1</code> is a directory, * <code>path2</code> must also be, and if <code>url1</code> is a file, * <code>path2</code> must also be. * <p/> * If <code>depth</code> is {@link SVNDepth#INFINITY}, diffs fully * recursively. Else if it is {@link SVNDepth#IMMEDIATES}, diffs the named * paths and their file children (if any), and diffs properties of * subdirectories, but does not descend further into the subdirectories. * Else if {@link SVNDepth#FILES}, behaves as if for * {@link SVNDepth#IMMEDIATES} except doesn't diff properties of * subdirectories. If {@link SVNDepth#EMPTY}, diffs exactly the named paths * but nothing underneath them. * <p/> * <code>useAncestry</code> controls whether or not items being diffed will * be checked for relatedness first. Unrelated items are typically * transmitted to the editor as a deletion of one thing and the addition of * another, but if this flag is <span class="javakeyword">true</span>, * unrelated items will be diffed as if they were related. * <p/> * If {@link ISVNDiffGenerator#isDiffDeleted()} returns <span * class="javakeyword">true</span>, then no diff output will be generated on * deleted files. * <p/> * Generated headers are encoded using * {@link ISVNDiffGenerator#getEncoding()}. * <p/> * Diffs output will not be generated for binary files, unless * {@link ISVNDiffGenerator#isForcedBinaryDiff()} is <span * class="javakeyword">true</span>, in which case diffs will be shown * regardless of the content types. * <p/> * If this client object uses {@link DefaultSVNDiffGenerator} then a caller * can set {@link SVNDiffOptions} to it which will be used to pass * additional options to the diff processes invoked to compare files. * <p/> * <code>changeLists</code> is a collection of <code>String</code> * changelist names, used as a restrictive filter on items whose differences * are reported; that is, doesn't generate diffs about any item unless it's * a member of one of those changelists. If <code>changeLists</code> is * empty (or <span class="javakeyword">null</span>), no changelist filtering * occurs. * <p/> * Note: changelist filtering only applies to diffs in which at least one * side of the diff represents working copy data. * <p/> * If both <code>rM</code> is either {@link SVNRevision#WORKING} or * {@link SVNRevision#BASE}, then it will be a url-against-wc; otherwise, a * url-against-url diff. * * @param url1 a * repository location URL * @param rNa * revision of <code>url1</code> * @param path2 a * WC path that is to be compared against <code>url1</code> * @param rMa * revision of <code>path2</code> * @param depth tree * depth to process * @param useAncestry if * <span class="javakeyword">true</span> then the paths ancestry * will be noticed while calculating differences, otherwise not * @param result the * target {@link java.io.OutputStream} where the differences will * be written to * @param changeLists collection * with changelist names * @throws SVNException in * the following cases: * <ul> * <li/>exception with {@link SVNErrorCode#CLIENT_BAD_REVISION} * error code - if either <code>rN</code> or <code>rM</code> is * {@link SVNRevision#isValid() invalid} * </ul> * @since 1.2, SVN 1.5 */ public void doDiff(SVNURL url1, SVNRevision rN, File path2, SVNRevision rM, SVNDepth depth, boolean useAncestry, OutputStream result, Collection changeLists) throws SVNException { if (!rN.isValid() || !rM.isValid()) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.CLIENT_BAD_REVISION, "Both rN and rM revisions should be specified"); SVNErrorManager.error(err, SVNLogType.DEFAULT); } getDiffGenerator().init(url1.toString(), path2.getAbsolutePath()); if (rM == SVNRevision.BASE || rM == SVNRevision.WORKING) { doDiffURLWC(url1, rN, SVNRevision.UNDEFINED, path2, rM, false, depth, useAncestry, result, changeLists); } else { doDiffURLURL(url1, null, rN, null, path2, rM, SVNRevision.UNDEFINED, depth, useAncestry, result); } } /** * Generates the differences comparing either the specified Working Copy * paths or their repository location URLs (any combinations are possible) * in the specified revisions and writes the result to the provided output * stream. * <p> * If both <code>rN</code> and <code>rM</code> are local revisions (see * {@link SVNRevision#isLocal()}), then a Working Copy <code>path2</code> is * compared against a Working Copy <code>path1</code>. * <p> * If <code>rN</code> is a local revision but <code>rM</code> is not, then * the repository location URL of <code>path2</code> as it is in the * revision represented by <code>rM</code> is compared against the Working * Copy <code>path1</code>. * <p> * If <code>rM</code> is a local revision but <code>rN</code> is not, then * the Working Copy <code>path2</code> is compared against the repository * location URL of <code>path1</code> as it is in the revision represented * by <code>rN</code>. * <p> * If both <code>rN</code> and <code>rM</code> are non-local revisions, then * the repository location URL of <code>path2</code> in revision * <code>rM</code> is compared against the repository location URL of * <code>path1</code> in revision <code>rN</code>. * * @param path1 a * WC path * @param rNa * revision of <code>path1</code> * @param path2 a * WC path that is to be compared against <code>path1</code> * @param rMa * revision of <code>path2</code> * @param recursive * <span class="javakeyword">true</span> to descend recursively * @param useAncestry if * <span class="javakeyword">true</span> then the paths ancestry * will be noticed while calculating differences, otherwise not * @param result the * target {@link java.io.OutputStream} where the differences will * be written to * @throws SVNException if * one of the following is true: * <ul> * <li>at least one of <code>rN</code> and <code>rM</code> is * invalid <li><code>path1</code> is not under version control * <li><code>path1</code> has no URL <li><code>path2</code> is * not under version control <li><code>path2</code> has no URL * <li>the repository location of <code>path1</code> was not * found in <code>rN</code> <li>the repository location of * <code>path2</code> was not found in <code>rM</code> <li>both * <code>rN</code> and <code>rM</code> are local, but either * <code>path1</code> does not equal <code>path2</code>, or * <code>rN</code> is not {@link SVNRevision#BASE}, or <code>rM * </code> is not {@link SVNRevision#WORKING} * </ul> * @deprecated use * {@link #doDiff(File,SVNRevision,File,SVNRevision,SVNDepth,boolean,OutputStream,Collection)} * instead */ public void doDiff(File path1, SVNRevision rN, File path2, SVNRevision rM, boolean recursive, boolean useAncestry, OutputStream result) throws SVNException { doDiff(path1, rN, path2, rM, SVNDepth.getInfinityOrFilesDepth(recursive), useAncestry, result, null); } /** * Produces diff output which describes the delta between <code>path1</code> * /<code>rN</code> and <code>path2</code>/<code>rM</code>. Writes the * output of the diff to <code>result</code>. * <p/> * If this client object uses {@link DefaultSVNDiffGenerator} and there was * a non-<span class="javakeyword">null</span> * {@link DefaultSVNDiffGenerator#setBasePath(File) base path} provided to * it, the original path and modified path will have this base path stripped * from the front of the respective paths. If the base path is not <span * class="javakeyword">null</span> but is not a parent path of the target, * an exception with the {@link SVNErrorCode#BAD_RELATIVE_PATH} error code * is thrown. * <p/> * <code>path1</code> and <code>path2</code> must both represent the same * node kind -- that is, if <code>path1</code> is a directory, * <code>path2</code> must also be, and if <code>path1</code> is a file, * <code>path2</code> must also be. * <p/> * If <code>depth</code> is {@link SVNDepth#INFINITY}, diffs fully * recursively. Else if it is {@link SVNDepth#IMMEDIATES}, diffs the named * paths and their file children (if any), and diffs properties of * subdirectories, but does not descend further into the subdirectories. * Else if {@link SVNDepth#FILES}, behaves as if for * {@link SVNDepth#IMMEDIATES} except doesn't diff properties of * subdirectories. If {@link SVNDepth#EMPTY}, diffs exactly the named paths * but nothing underneath them. * <p/> * <code>useAncestry</code> controls whether or not items being diffed will * be checked for relatedness first. Unrelated items are typically * transmitted to the editor as a deletion of one thing and the addition of * another, but if this flag is <span class="javakeyword">true</span>, * unrelated items will be diffed as if they were related. * <p/> * If {@link ISVNDiffGenerator#isDiffDeleted()} returns <span * class="javakeyword">true</span>, then no diff output will be generated on * deleted files. * <p/> * Generated headers are encoded using * {@link ISVNDiffGenerator#getEncoding()}. * <p/> * Diffs output will not be generated for binary files, unless * {@link ISVNDiffGenerator#isForcedBinaryDiff()} is <span * class="javakeyword">true</span>, in which case diffs will be shown * regardless of the content types. * <p/> * If this client object uses {@link DefaultSVNDiffGenerator} then a caller * can set {@link SVNDiffOptions} to it which will be used to pass * additional options to the diff processes invoked to compare files. * <p/> * <code>changeLists</code> is a collection of <code>String</code> * changelist names, used as a restrictive filter on items whose differences * are reported; that is, doesn't generate diffs about any item unless it's * a member of one of those changelists. If <code>changeLists</code> is * empty (or <span class="javakeyword">null</span>), no changelist filtering * occurs. * <p/> * Note: changelist filtering only applies to diffs in which at least one * side of the diff represents working copy data. * <p/> * If both <code>rN</code> and <code>rM</code> are either * {@link SVNRevision#WORKING} or {@link SVNRevision#BASE}, then it will be * a wc-against-wc diff operation, in which case no repository access is * needed. If only <code>rN</code> or <code>rM</code> is, then it will be a * wc-against-url or url-against-wc diff correspondingly; if neither - a * url-against-url diff. * * @param path1 a * WC path * @param rNa * revision of <code>path1</code> * @param path2 a * WC path that is to be compared against <code>path1</code> * @param rMa * revision of <code>path2</code> * @param depth tree * depth to process * @param useAncestry if * <span class="javakeyword">true</span> then the paths ancestry * will be noticed while calculating differences, otherwise not * @param result the * target {@link java.io.OutputStream} where the differences will * be written to * @param changeLists collection * with changelist names * @throws SVNException in * the following cases: * <ul> * <li/>exception with {@link SVNErrorCode#CLIENT_BAD_REVISION} * error code - if either <code>rN</code> or <code>rM</code> is * {@link SVNRevision#isValid() invalid} * </ul> * @since 1.2, SVN 1.5 */ public void doDiff(File path1, SVNRevision rN, File path2, SVNRevision rM, SVNDepth depth, boolean useAncestry, OutputStream result, Collection changeLists) throws SVNException { if (!rN.isValid() || !rM.isValid()) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.CLIENT_BAD_REVISION, "Both rN and rM revisions should be specified"); SVNErrorManager.error(err, SVNLogType.DEFAULT); } boolean isPath1Local = rN == SVNRevision.WORKING || rN == SVNRevision.BASE; boolean isPath2Local = rM == SVNRevision.WORKING || rM == SVNRevision.BASE; getDiffGenerator().init(path1.getAbsolutePath(), path2.getAbsolutePath()); if (isPath1Local && isPath2Local) { doDiffWCWC(path1, rN, path2, rM, depth, useAncestry, result, changeLists); } else if (isPath1Local) { doDiffURLWC(path2, rM, SVNRevision.UNDEFINED, path1, rN, true, depth, useAncestry, result, changeLists); } else if (isPath2Local) { doDiffURLWC(path1, rN, SVNRevision.UNDEFINED, path2, rM, false, depth, useAncestry, result, changeLists); } else { doDiffURLURL(null, path1, rN, null, path2, rM, SVNRevision.UNDEFINED, depth, useAncestry, result); } } /** * Diffs one path against another one providing short status-like change * information to the provided handler. This method functionality is * equivalent to the 'svn diff --summarize' command. * * @param path1 the * path of a left-hand item to diff * @param rNa * revision of <code>path1</code> * @param path2 the * path of a right-hand item to diff * @param rMa * revision of <code>path2</code> * @param recursivecontrols * whether operation must recurse or not * @param useAncestry if * <span class="javakeyword">true</span> then the paths ancestry * will be noticed while calculating differences, otherwise not * @param handlera * diff status handler * @throws SVNException * @since 1.1, new in Subversion 1.4 * @deprecated use * {@link #doDiffStatus(File,SVNRevision,File,SVNRevision,SVNDepth,boolean,ISVNDiffStatusHandler)} * instead */ public void doDiffStatus(File path1, SVNRevision rN, File path2, SVNRevision rM, boolean recursive, boolean useAncestry, ISVNDiffStatusHandler handler) throws SVNException { doDiffStatus(path1, rN, path2, rM, SVNDepth.getInfinityOrFilesDepth(recursive), useAncestry, handler); } /** * Produces a diff summary which lists the changed items between * <code>path</code> in peg revision <code>pegRevision</code>, as it changed * between <code>rN</code> and <code>rM</code>. * <p/> * If <code>pegRevision</code> is {@link SVNRevision#isValid() invalid}, * behaves identically to * {@link #doDiffStatus(File,SVNRevision,File,SVNRevision,SVNDepth,boolean,ISVNDiffStatusHandler)} * , using <code>path</code> for both of that method's <code>path1</code> * and <code>path2</code> argments. * <p/> * The method may report false positives if <code>useAncestry</code> is * <span class="javakeyword">false</span>, as described in the documentation * for * {@link #doDiffStatus(File,SVNRevision,File,SVNRevision,SVNDepth,boolean,ISVNDiffStatusHandler)}. * <p/> * Calls <code>handler</code> for each difference with an * {@link SVNDiffStatus} object describing the difference. * <p/> * See * {@link #doDiff(File,SVNRevision,SVNRevision,SVNRevision,SVNDepth,boolean,OutputStream,Collection)} * for a description of the other parameters. * * @param pathworking * copy path * @param rNleft * -hand revision * @param rMright * -hand revision * @param pegRevision a * revision in which the repository location of <code>path</code> * is first looked up * @param depth tree * depth to process * @param useAncestry if * <span class="javakeyword">true</span> then the paths ancestry * will be noticed while calculating differences, otherwise not * @param handlera * diff status handler * @throws SVNException * @since 1.2, SVN 1.5 */ public void doDiffStatus(File path, SVNRevision rN, SVNRevision rM, SVNRevision pegRevision, SVNDepth depth, boolean useAncestry, ISVNDiffStatusHandler handler) throws SVNException { if (handler == null) { return; } if (pegRevision == null) { pegRevision = SVNRevision.UNDEFINED; } if (!rN.isValid() || !rM.isValid()) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.CLIENT_BAD_REVISION, "Not all required revisions are specified"); SVNErrorManager.error(err, SVNLogType.DEFAULT); } boolean isPath1Local = rN == SVNRevision.WORKING || rN == SVNRevision.BASE; boolean isPath2Local = rM == SVNRevision.WORKING || rM == SVNRevision.BASE; if (isPath1Local || isPath2Local) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.UNSUPPORTED_FEATURE, "Summarizing diff can only compare repository to repository"); SVNErrorManager.error(err, SVNLogType.DEFAULT); } doDiffURLURL(null, path, rN, null, path, rM, pegRevision, depth, useAncestry, handler); } /** * Produces a diff summary which lists the changed items between * <code>path1</code>/<code>rN</code> and <code>path2</code>/<code>rM</code> * without creating text deltas. * <p/> * The function may report false positives if <code>ignoreAncestry</code> is * <span class="javakeyword">false</span>, since a file might have been * modified between two revisions, but still have the same contents. * <p/> * Calls <code>handler</code> for each difference with an * {@link SVNDiffStatus} object describing the difference. * <p/> * See * {@link #doDiff(File,SVNRevision,File,SVNRevision,SVNDepth,boolean,OutputStream,Collection)} * for a description of the other parameters. * * @param path1 the * path of a left-hand item to diff * @param rNa * revision of <code>path1</code> * @param path2 the * path of a right-hand item to diff * @param rMa * revision of <code>path2</code> * @param depth tree * depth to process * @param useAncestry if * <span class="javakeyword">true</span> then the paths ancestry * will be noticed while calculating differences, otherwise not * @param handlera * diff status handler * @throws SVNException in * the following cases: * <ul> * <li/>exception with {@link SVNErrorCode#CLIENT_BAD_REVISION} * error code - if either <code>rN</code> or <code>rM</code> is * {@link SVNRevision#isValid() invalid} <li/>exception with * {@link SVNErrorCode#UNSUPPORTED_FEATURE} error code - if * either of <code>rM</code> or </code>rN</code> is either * {@link SVNRevision#WORKING} or {@link SVNRevision#BASE} * </ul> * @since 1.2, SVN 1.5 */ public void doDiffStatus(File path1, SVNRevision rN, File path2, SVNRevision rM, SVNDepth depth, boolean useAncestry, ISVNDiffStatusHandler handler) throws SVNException { if (handler == null) { return; } if (!rN.isValid() || !rM.isValid()) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.CLIENT_BAD_REVISION, "Not all required revisions are specified"); SVNErrorManager.error(err, SVNLogType.DEFAULT); } boolean isPath1Local = rN == SVNRevision.WORKING || rN == SVNRevision.BASE; boolean isPath2Local = rM == SVNRevision.WORKING || rM == SVNRevision.BASE; if (isPath1Local || isPath2Local) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.UNSUPPORTED_FEATURE, "Summarizing diff can only compare repository to repository"); SVNErrorManager.error(err, SVNLogType.DEFAULT); } doDiffURLURL(null, path1, rN, null, path2, rM, SVNRevision.UNDEFINED, depth, useAncestry, handler); } /** * Diffs a path against a url providing short status-like change information * to the provided handler. This method functionality is equivalent to the * 'svn diff --summarize' command. * * @param path1 the * path of a left-hand item to diff * @param rNa * revision of <code>path1</code> * @param url2 the * url of a right-hand item to diff * @param rMa * revision of <code>url2</code> * @param recursivecontrols * whether operation must recurse or not * @param useAncestry if * <span class="javakeyword">true</span> then the paths ancestry * will be noticed while calculating differences, otherwise not * @param handlera * diff status handler * @throws SVNException * @since 1.1, new in Subversion 1.4 * @deprecated use * {@link #doDiffStatus(File,SVNRevision,SVNURL,SVNRevision,SVNDepth,boolean,ISVNDiffStatusHandler)} * instead */ public void doDiffStatus(File path1, SVNRevision rN, SVNURL url2, SVNRevision rM, boolean recursive, boolean useAncestry, ISVNDiffStatusHandler handler) throws SVNException { doDiffStatus(path1, rN, url2, rM, SVNDepth.getInfinityOrFilesDepth(recursive), useAncestry, handler); } /** * Produces a diff summary which lists the changed items between * <code>path1</code>/<code>rN</code> and <code>url2</code>/<code>rM</code> * without creating text deltas. * <p/> * The function may report false positives if <code>ignoreAncestry</code> is * <span class="javakeyword">false</span>, since a file might have been * modified between two revisions, but still have the same contents. * <p/> * Calls <code>handler</code> for each difference with an * {@link SVNDiffStatus} object describing the difference. * <p/> * See * {@link #doDiff(File,SVNRevision,SVNURL,SVNRevision,SVNDepth,boolean,OutputStream,Collection)} * for a description of the other parameters. * * @param path1 the * path of a left-hand item to diff * @param rNa * revision of <code>path1</code> * @param url2repository * url as a right-hand item * @param rMa * revision of <code>url2</code> * @param depth tree * depth to process * @param useAncestry if * <span class="javakeyword">true</span> then the paths ancestry * will be noticed while calculating differences, otherwise not * @param handlera * diff status handler * @throws SVNException in * the following cases: * <ul> * <li/>exception with {@link SVNErrorCode#CLIENT_BAD_REVISION} * error code - if either <code>rN</code> or <code>rM</code> is * {@link SVNRevision#isValid() invalid} <li/>exception with * {@link SVNErrorCode#UNSUPPORTED_FEATURE} error code - if * either of <code>rM</code> or </code>rN</code> is either * {@link SVNRevision#WORKING} or {@link SVNRevision#BASE} * </ul> * @since 1.2, SVN 1.5 */ public void doDiffStatus(File path1, SVNRevision rN, SVNURL url2, SVNRevision rM, SVNDepth depth, boolean useAncestry, ISVNDiffStatusHandler handler) throws SVNException { if (handler == null) { return; } if (!rN.isValid() || !rM.isValid()) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.CLIENT_BAD_REVISION, "Not all required revisions are specified"); SVNErrorManager.error(err, SVNLogType.DEFAULT); } if (rN == SVNRevision.BASE || rN == SVNRevision.WORKING) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.UNSUPPORTED_FEATURE, "Summarizing diff can only compare repository to repository"); SVNErrorManager.error(err, SVNLogType.DEFAULT); } else { doDiffURLURL(null, path1, rN, url2, null, rM, SVNRevision.UNDEFINED, depth, useAncestry, handler); } } /** * Diffs a url against a path providing short status-like change information * to the provided handler. This method functionality is equivalent to the * 'svn diff --summarize' command. * * @param url1 the * url of a left-hand item to diff * @param rNa * revision of <code>url1</code> * @param path2 the * path of a right-hand item to diff * @param rMa * revision of <code>path2</code> * @param recursivecontrols * whether operation must recurse or not * @param useAncestry if * <span class="javakeyword">true</span> then the paths ancestry * will be noticed while calculating differences, otherwise not * @param handlera * diff status handler * @throws SVNException * @since 1.1, new in Subversion 1.4 * @deprecated use * {@link #doDiffStatus(SVNURL,SVNRevision,File,SVNRevision,SVNDepth,boolean,ISVNDiffStatusHandler)} * instead */ public void doDiffStatus(SVNURL url1, SVNRevision rN, File path2, SVNRevision rM, boolean recursive, boolean useAncestry, ISVNDiffStatusHandler handler) throws SVNException { doDiffStatus(url1, rN, path2, rM, SVNDepth.getInfinityOrFilesDepth(recursive), useAncestry, handler); } /** * Produces a diff summary which lists the changed items between * <code>url1</code>/<code>rN</code> and <code>path2</code>/<code>rM</code> * without creating text deltas. * <p/> * The function may report false positives if <code>ignoreAncestry</code> is * <span class="javakeyword">false</span>, since a file might have been * modified between two revisions, but still have the same contents. * <p/> * Calls <code>handler</code> for each difference with an * {@link SVNDiffStatus} object describing the difference. * <p/> * See * {@link #doDiff(SVNURL,SVNRevision,File,SVNRevision,SVNDepth,boolean,OutputStream,Collection)} * for a description of the other parameters. * * @param url1repository * url as a left-hand item * @param rNa * revision of <code>url1</code> * @param path2 the * path of a right-hand item to diff * @param rMa * revision of <code>path2</code> * @param depth tree * depth to process * @param useAncestry if * <span class="javakeyword">true</span> then the paths ancestry * will be noticed while calculating differences, otherwise not * @param handlera * diff status handler * @throws SVNException in * the following cases: * <ul> * <li/>exception with {@link SVNErrorCode#CLIENT_BAD_REVISION} * error code - if either <code>rN</code> or <code>rM</code> is * {@link SVNRevision#isValid() invalid} <li/>exception with * {@link SVNErrorCode#UNSUPPORTED_FEATURE} error code - if * either of <code>rM</code> or </code>rN</code> is either * {@link SVNRevision#WORKING} or {@link SVNRevision#BASE} * </ul> * @since 1.2, SVN 1.5 */ public void doDiffStatus(SVNURL url1, SVNRevision rN, File path2, SVNRevision rM, SVNDepth depth, boolean useAncestry, ISVNDiffStatusHandler handler) throws SVNException { if (handler == null) { return; } if (!rN.isValid() || !rM.isValid()) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.CLIENT_BAD_REVISION, "Both rN and rM revisions should be specified"); SVNErrorManager.error(err, SVNLogType.DEFAULT); } if (rM == SVNRevision.BASE || rM == SVNRevision.WORKING) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.UNSUPPORTED_FEATURE, "Summarizing diff can only compare repository to repository"); SVNErrorManager.error(err, SVNLogType.DEFAULT); } else { doDiffURLURL(url1, null, rN, null, path2, rM, SVNRevision.UNDEFINED, depth, useAncestry, handler); } } /** * Diffs one url against another one providing short status-like change * information to the provided handler. This method functionality is * equivalent to the 'svn diff --summarize' command. * * @param url1 the * url of a left-hand item to diff * @param rNa * revision of <code>url1</code> * @param url2 the * url of a right-hand item to diff * @param rMa * revision of <code>url2</code> * @param recursivecontrols * whether operation must recurse or not * @param useAncestry if * <span class="javakeyword">true</span> then the paths ancestry * will be noticed while calculating differences, otherwise not * @param handlera * diff status handler * @throws SVNException * @since 1.1, new in Subversion 1.4 * @deprecated use * {@link #doDiffStatus(SVNURL,SVNRevision,SVNURL,SVNRevision,SVNDepth,boolean,ISVNDiffStatusHandler)} * instead */ public void doDiffStatus(SVNURL url1, SVNRevision rN, SVNURL url2, SVNRevision rM, boolean recursive, boolean useAncestry, ISVNDiffStatusHandler handler) throws SVNException { doDiffStatus(url1, rN, url2, rM, SVNDepth.getInfinityOrFilesDepth(recursive), useAncestry, handler); } /** * Produces a diff summary which lists the changed items between * <code>url</code> in peg revision <code>pegRevision</code>, as it changed * between <code>rN</code> and <code>rM</code>. * <p/> * If <code>pegRevision</code> is {@link SVNRevision#isValid() invalid}, * behaves identically to * {@link #doDiffStatus(SVNURL,SVNRevision,SVNURL,SVNRevision,SVNDepth,boolean,ISVNDiffStatusHandler)} * , using <code>url</code> for both of that method's <code>url1</code> and * <code>url2</code> argments. * <p/> * The method may report false positives if <code>useAncestry</code> is * <span class="javakeyword">false</span>, as described in the documentation * for * {@link #doDiffStatus(SVNURL,SVNRevision,SVNURL,SVNRevision,SVNDepth,boolean,ISVNDiffStatusHandler)}. * <p/> * Calls <code>handler</code> for each difference with an * {@link SVNDiffStatus} object describing the difference. * <p/> * See * {@link #doDiff(SVNURL,SVNRevision,SVNRevision,SVNRevision,SVNDepth,boolean,OutputStream)} * for a description of the other parameters. * * @param urlrepository * url * @param rNleft * -hand revision * @param rMright * -hand revision * @param pegRevision a * revision in which the repository location of <code>path</code> * is first looked up * @param depth tree * depth to process * @param useAncestry if * <span class="javakeyword">true</span> then the paths ancestry * will be noticed while calculating differences, otherwise not * @param handlera * diff status handler * @throws SVNException * @since 1.2, SVN 1.5 */ public void doDiffStatus(SVNURL url, SVNRevision rN, SVNRevision rM, SVNRevision pegRevision, SVNDepth depth, boolean useAncestry, ISVNDiffStatusHandler handler) throws SVNException { if (handler == null) { return; } if (pegRevision == null) { pegRevision = SVNRevision.UNDEFINED; } if (!rN.isValid() || !rM.isValid()) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.CLIENT_BAD_REVISION, "Both rN and rM revisions should be specified"); SVNErrorManager.error(err, SVNLogType.DEFAULT); } doDiffURLURL(url, null, rN, url, null, rM, pegRevision, depth, useAncestry, handler); } /** * Produces a diff summary which lists the changed items between * <code>url1</code>/<code>rN</code> and <code>url2</code>/<code>rM</code> * without creating text deltas. * <p/> * The function may report false positives if <code>ignoreAncestry</code> is * <span class="javakeyword">false</span>, since a file might have been * modified between two revisions, but still have the same contents. * <p/> * Calls <code>handler</code> for each difference with an * {@link SVNDiffStatus} object describing the difference. * <p/> * See * {@link #doDiff(SVNURL,SVNRevision,SVNURL,SVNRevision,SVNDepth,boolean,OutputStream)} * for a description of the other parameters. * * @param url1 the * url of a left-hand item to diff * @param rNa * revision of <code>url1</code> * @param url2 the * url of a right-hand item to diff * @param rMa * revision of <code>url2</code> * @param depth tree * depth to process * @param useAncestry if * <span class="javakeyword">true</span> then the paths ancestry * will be noticed while calculating differences, otherwise not * @param handlera * diff status handler * @throws SVNException * @since 1.2, SVN 1.5 */ public void doDiffStatus(SVNURL url1, SVNRevision rN, SVNURL url2, SVNRevision rM, SVNDepth depth, boolean useAncestry, ISVNDiffStatusHandler handler) throws SVNException { if (handler == null) { return; } if (!rN.isValid() || !rM.isValid()) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.CLIENT_BAD_REVISION, "Both rN and rM revisions should be specified"); SVNErrorManager.error(err, SVNLogType.DEFAULT); } doDiffURLURL(url1, null, rN, url2, null, rM, SVNRevision.UNDEFINED, depth, useAncestry, handler); } /** * Applies the differences between two sources (using Working Copy paths to * get corresponding URLs of the sources) to a Working Copy path. * <p> * Corresponds to the SVN command line client's <code>'svn merge sourceWCPATH1@rev1 sourceWCPATH2@rev2 WCPATH'</code> command. * <p> * If you need only to try merging your file(s) without actual merging, you * should set <code>dryRun</code> to <span class="javakeyword">true</span>. * Your event handler will be dispatched status type information on the * target path(s). If a path can be successfully merged, the status type * will be {@link SVNStatusType#MERGED} for that path. * * @param path1 the * first source path * @param revision1 a * revision of <code>path1</code> * @param path2 the * second source path which URL is to be compared against the URL * of <code>path1</code> * @param revision2 a * revision of <code>path2</code> * @param dstPath the * target path to which the result should be applied * @param recursive * <span class="javakeyword">true</span> to descend recursively * @param useAncestry if * <span class="javakeyword">true</span> then the paths ancestry * will be noticed while calculating differences, otherwise not * @param force * <span class="javakeyword">true</span> to force the operation * to run * @param dryRun if * <span class="javakeyword">true</span> then only tries the * operation to run (to find out if a file can be merged * successfully) * @throws SVNException if * one of the following is true: * <ul> * <li>at least one of <code>revision1</code> and <code> * revision2</code> is invalid <li><code>path1</code> has no URL * <li><code>path2</code> has no URL <li>the repository location * of <code>path1</code> was not found in <code>revision1</code> * <li>the repository location of <code>path2</code> was not * found in <code>revision2</code> <li><code>dstPath</code> is * not under version control * </ul> * @deprecated use * {@link #doMerge(File,SVNRevision,File,SVNRevision,File,SVNDepth,boolean,boolean,boolean,boolean)} * instead */ public void doMerge(File path1, SVNRevision revision1, File path2, SVNRevision revision2, File dstPath, boolean recursive, boolean useAncestry, boolean force, boolean dryRun) throws SVNException { doMerge(path1, revision1, path2, revision2, dstPath, SVNDepth.getInfinityOrFilesDepth(recursive), useAncestry, force, dryRun, false); } /** * Merges changes from <code>path1</code>/<code>revision1</code> to * <code>path2</code>/<code>revision2</code> into the working-copy path * <code>dstPath</code>. * <p/> * <code>path1</code> and <code>path2</code> must both represent the same * node kind - that is, if <code>path1</code> is a directory, * <code>path2</code> must also be, and if <code>path1</code> is a file, * <code>path2</code> must also be. * <p/> * If <code>depth</code> is {@link SVNDepth#INFINITY}, merges fully * recursively. Else if {@link SVNDepth#IMMEDIATES}, merges changes at most * to files that are immediate children of <code>dstPath</code> and to * directory properties of <code>dstPath</code> and its immediate * subdirectory children. Else if {@link SVNDepth#FILES}, merges at most to * immediate file children of <code>dstPath</code> and to * <code>dstPath</code> itself. Else if {@link SVNDepth#EMPTY}, applies * changes only to <code>dstPath</code> (i.e., directory property changes * only). * <p/> * If <code>depth</code> is {@link SVNDepth#UNKNOWN}, uses the depth of * <code>dstPath</code>. * <p/> * Uses <code>useAncestry</code> to control whether or not items being * diffed will be checked for relatedness first. Unrelated items are * typically transmitted to the editor as a deletion of one thing and the * addition of another, but if this flag is <span * class="javakeyword">true</span>, unrelated items will be diffed as if * they were related. * <p/> * If <code>force</code> is not set and the merge involves deleting locally * modified or unversioned items the operation will fail. If * <code>force</code> is set such items will be deleted. * <p/> * {@link #getMergeOptions() merge options} is used to pass arguments to the * merge processes (internal or external). * <p/> * If the caller's {@link ISVNEventHandler} is not <span * class="javakeyword">null</span>, then it will be called once for each * merged target. * <p> * If <code>recordOnly</code> is <span class="javakeyword">true</span>, the * merge isn't actually performed, but the mergeinfo for the revisions which * would've been merged is recorded in the working copy (and must be * subsequently committed back to the repository). * <p/> * If <code>dryRun</code> is <span class="javakeyword">true</span>, the * merge is carried out, and full notification feedback is provided, but the * working copy is not modified. * <p/> * Note: this method requires repository access. * * @param path1 left * -hand working copy path * @param revision1 revision * of <code>path1</code> * @param path2 right * -hand working copy path * @param revision2 revision * of <code>path2</code> * @param dstPath target * working copy path * @param depth tree * depth to process * @param useAncestry if * <span class="javakeyword">true</span> then the paths ancestry * will be noticed while calculating differences, otherwise not * @param force * <span class="javakeyword">true</span> to force the operation * to run * @param dryRun if * <span class="javakeyword">true</span> then runs merge without * any file changes * @param recordOnlyif * <span class="javakeyword">true</span>, records only the result * of merge - mergeinfo data * @throws SVNException in * the following cases: * <ul> * <li/>exception with {@link SVNErrorCode#CLIENT_BAD_REVISION} * error code - if either <code>revision1</code> or <code> * revision2</code> is {@link SVNRevision#isValid() invalid} * <li/>exception with {@link SVNErrorCode#ENTRY_MISSING_URL} * error code - if failed to retrieve url of either <code>path1 * </code> or <code>path2</code> * </ul> * @since 1.2, SVN 1.5 */ public void doMerge(File path1, SVNRevision revision1, File path2, SVNRevision revision2, File dstPath, SVNDepth depth, boolean useAncestry, boolean force, boolean dryRun, boolean recordOnly) throws SVNException { path1 = path1.getAbsoluteFile(); path2 = path2.getAbsoluteFile(); dstPath = dstPath.getAbsoluteFile(); SVNURL url1 = getURL(path1); if (url1 == null) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.ENTRY_MISSING_URL, "''{0}'' has no URL", path1); SVNErrorManager.error(err, SVNLogType.WC); } SVNURL url2 = getURL(path2); if (url2 == null) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.ENTRY_MISSING_URL, "''{0}'' has no URL", path2); SVNErrorManager.error(err, SVNLogType.WC); } runMerge(url1, revision1, url2, revision2, dstPath, depth, dryRun, force, !useAncestry, recordOnly); } /** * Applies the differences between two sources (a source URL against the * repository location URL of a source Working Copy path) to a Working Copy * path. * <p> * If you need only to try merging your file(s) without actual merging, you * should set <code>dryRun</code> to <span class="javakeyword">true</span>. * Your event handler will be dispatched status type information on the * target path(s). If a path can be successfully merged, the status type * will be {@link SVNStatusType#MERGED} for that path. * * @param path1 the * first source - a WC path * @param revision1 a * revision of <code>path1</code> * @param url2 the * second source - a URL that is to be compared against the URL * of <code>path1</code> * @param revision2 a * revision of <code>url2</code> * @param dstPath the * target path to which the result should be applied * @param recursive * <span class="javakeyword">true</span> to descend recursively * @param useAncestry if * <span class="javakeyword">true</span> then the paths ancestry * will be noticed while calculating differences, otherwise not * @param force * <span class="javakeyword">true</span> to force the operation * to run * @param dryRun if * <span class="javakeyword">true</span> then only tries the * operation to run (to find out if a file can be merged * successfully) * @throws SVNException if * one of the following is true: * <ul> * <li>at least one of <code>revision1</code> and <code> * revision2</code> is invalid <li><code>path1</code> has no URL * <li>the repository location of <code>path1</code> was not * found in <code>revision1</code> <li><code>url2</code> was not * found in <code>revision2</code> <li><code>dstPath</code> is * not under version control * </ul> * @deprecated use * {@link #doMerge(File,SVNRevision,SVNURL,SVNRevision,File,SVNDepth,boolean,boolean,boolean,boolean)} * instead */ public void doMerge(File path1, SVNRevision revision1, SVNURL url2, SVNRevision revision2, File dstPath, boolean recursive, boolean useAncestry, boolean force, boolean dryRun) throws SVNException { doMerge(path1, revision1, url2, revision2, dstPath, SVNDepth.getInfinityOrFilesDepth(recursive), useAncestry, force, dryRun, false); } /** * Merges changes from <code>path1</code>/<code>revision1</code> to * <code>url2</code>/<code>revision2</code> into the working-copy path * <code>dstPath</code>. * <p/> * <code>path1</code> and <code>url2</code> must both represent the same * node kind - that is, if <code>path1</code> is a directory, * <code>url2</code> must also be, and if <code>path1</code> is a file, * <code>url2</code> must also be. * <p/> * If <code>depth</code> is {@link SVNDepth#INFINITY}, merges fully * recursively. Else if {@link SVNDepth#IMMEDIATES}, merges changes at most * to files that are immediate children of <code>dstPath</code> and to * directory properties of <code>dstPath</code> and its immediate * subdirectory children. Else if {@link SVNDepth#FILES}, merges at most to * immediate file children of <code>dstPath</code> and to * <code>dstPath</code> itself. Else if {@link SVNDepth#EMPTY}, applies * changes only to <code>dstPath</code> (i.e., directory property changes * only). * <p/> * If <code>depth</code> is {@link SVNDepth#UNKNOWN}, uses the depth of * <code>dstPath</code>. * <p/> * Uses <code>useAncestry</code> to control whether or not items being * diffed will be checked for relatedness first. Unrelated items are * typically transmitted to the editor as a deletion of one thing and the * addition of another, but if this flag is <span * class="javakeyword">true</span>, unrelated items will be diffed as if * they were related. * <p/> * If <code>force</code> is not set and the merge involves deleting locally * modified or unversioned items the operation will fail. If * <code>force</code> is set such items will be deleted. * <p/> * {@link #getMergeOptions() merge options} is used to pass arguments to the * merge processes (internal or external). * <p/> * If the caller's {@link ISVNEventHandler} is not <span * class="javakeyword">null</span>, then it will be called once for each * merged target. * <p> * If <code>recordOnly</code> is <span class="javakeyword">true</span>, the * merge isn't actually performed, but the mergeinfo for the revisions which * would've been merged is recorded in the working copy (and must be * subsequently committed back to the repository). * <p/> * If <code>dryRun</code> is <span class="javakeyword">true</span>, the * merge is carried out, and full notification feedback is provided, but the * working copy is not modified. * <p/> * Note: this method requires repository access. * * @param path1 left * -hand item - working copy path * @param revision1 revision * of <code>path1</code> * @param url2 right * -hand item - repository url * @param revision2 revision * of <code>url2</code> * @param dstPath target * working copy path * @param depth tree * depth to process * @param useAncestry if * <span class="javakeyword">true</span> then the paths ancestry * will be noticed while calculating differences, otherwise not * @param force * <span class="javakeyword">true</span> to force the operation * to run * @param dryRun if * <span class="javakeyword">true</span> then runs merge without * any file changes * @param recordOnlyif * <span class="javakeyword">true</span>, records only the result * of merge - mergeinfo data * @throws SVNException in * the following cases: * <ul> * <li/>exception with {@link SVNErrorCode#CLIENT_BAD_REVISION} * error code - if either <code>revision1</code> or <code> * revision2</code> is {@link SVNRevision#isValid() invalid} * <li/>exception with {@link SVNErrorCode#ENTRY_MISSING_URL} * error code - if failed to retrieve the repository url of * <code>path1</code> * </ul> * @since 1.2, SVN 1.5 */ public void doMerge(File path1, SVNRevision revision1, SVNURL url2, SVNRevision revision2, File dstPath, SVNDepth depth, boolean useAncestry, boolean force, boolean dryRun, boolean recordOnly) throws SVNException { path1 = path1.getAbsoluteFile(); dstPath = dstPath.getAbsoluteFile(); SVNURL url1 = getURL(path1); if (url1 == null) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.ENTRY_MISSING_URL, "''{0}'' has no URL", path1); SVNErrorManager.error(err, SVNLogType.WC); } runMerge(url1, revision1, url2, revision2, dstPath, depth, dryRun, force, !useAncestry, recordOnly); } /** * Applies the differences between two sources (the repository location URL * of a source Working Copy against a source URL) to a Working Copy path. * <p> * If you need only to try merging your file(s) without actual merging, you * should set <code>dryRun</code> to <span class="javakeyword">true</span>. * Your event handler will be dispatched status type information on the * target path(s). If a path can be successfully merged, the status type * will be {@link SVNStatusType#MERGED} for that path. * * @param url1 the * first source - a URL * @param revision1 a * revision of <code>url1</code> * @param path2 the * second source - a WC path that is to be compared against * <code>url1</code> * @param revision2 a * revision of <code>path2</code> * @param dstPath the * target path to which the result should be applied * @param recursive * <span class="javakeyword">true</span> to descend recursively * @param useAncestry if * <span class="javakeyword">true</span> then the paths ancestry * will be noticed while calculating differences, otherwise not * @param force * <span class="javakeyword">true</span> to force the operation * to run * @param dryRun if * <span class="javakeyword">true</span> then only tries the * operation to run (to find out if a file can be merged * successfully) * @throws SVNException if * one of the following is true: * <ul> * <li>at least one of <code>revision1</code> and <code> * revision2</code> is invalid <li><code>path2</code> has no URL * <li><code>url1</code> was not found in <code>revision1</code> * <li>the repository location of <code>path2</code> was not * found in <code>revision2</code> <li><code>dstPath</code> is * not under version control * </ul> * @deprecated use * {@link #doMerge(SVNURL,SVNRevision,File,SVNRevision,File,SVNDepth,boolean,boolean,boolean,boolean)} * instead */ public void doMerge(SVNURL url1, SVNRevision revision1, File path2, SVNRevision revision2, File dstPath, boolean recursive, boolean useAncestry, boolean force, boolean dryRun) throws SVNException { doMerge(url1, revision1, path2, revision2, dstPath, SVNDepth.getInfinityOrFilesDepth(recursive), useAncestry, force, dryRun, false); } /** * Merges changes from <code>url1</code>/<code>revision1</code> to * <code>path2</code>/<code>revision2</code> into the working-copy path * <code>dstPath</code>. * <p/> * <code>url1</code> and <code>path2</code> must both represent the same * node kind - that is, if <code>url1</code> is a directory, * <code>path2</code> must also be, and if <code>url1</code> is a file, * <code>path2</code> must also be. * <p/> * If <code>depth</code> is {@link SVNDepth#INFINITY}, merges fully * recursively. Else if {@link SVNDepth#IMMEDIATES}, merges changes at most * to files that are immediate children of <code>dstPath</code> and to * directory properties of <code>dstPath</code> and its immediate * subdirectory children. Else if {@link SVNDepth#FILES}, merges at most to * immediate file children of <code>dstPath</code> and to * <code>dstPath</code> itself. Else if {@link SVNDepth#EMPTY}, applies * changes only to <code>dstPath</code> (i.e., directory property changes * only). * <p/> * If <code>depth</code> is {@link SVNDepth#UNKNOWN}, uses the depth of * <code>dstPath</code>. * <p/> * Uses <code>useAncestry</code> to control whether or not items being * diffed will be checked for relatedness first. Unrelated items are * typically transmitted to the editor as a deletion of one thing and the * addition of another, but if this flag is <span * class="javakeyword">true</span>, unrelated items will be diffed as if * they were related. * <p/> * If <code>force</code> is not set and the merge involves deleting locally * modified or unversioned items the operation will fail. If * <code>force</code> is set such items will be deleted. * <p/> * {@link #getMergeOptions() merge options} is used to pass arguments to the * merge processes (internal or external). * <p/> * If the caller's {@link ISVNEventHandler} is not <span * class="javakeyword">null</span>, then it will be called once for each * merged target. * <p> * If <code>recordOnly</code> is <span class="javakeyword">true</span>, the * merge isn't actually performed, but the mergeinfo for the revisions which * would've been merged is recorded in the working copy (and must be * subsequently committed back to the repository). * <p/> * If <code>dryRun</code> is <span class="javakeyword">true</span>, the * merge is carried out, and full notification feedback is provided, but the * working copy is not modified. * <p/> * Note: this method requires repository access. * * @param url1 left * -hand item - repository url * @param revision1 revision * of <code>url1</code> * @param path2 right * -hand item - working copy path * @param revision2 revision * of <code>path2</code> * @param dstPath target * working copy path * @param depth tree * depth to process * @param useAncestry if * <span class="javakeyword">true</span> then the paths ancestry * will be noticed while calculating differences, otherwise not * @param force * <span class="javakeyword">true</span> to force the operation * to run * @param dryRun if * <span class="javakeyword">true</span> then runs merge without * any file changes * @param recordOnlyif * <span class="javakeyword">true</span>, records only the result * of merge - mergeinfo data * @throws SVNException in * the following cases: * <ul> * <li/>exception with {@link SVNErrorCode#CLIENT_BAD_REVISION} * error code - if either <code>revision1</code> or <code> * revision2</code> is {@link SVNRevision#isValid() invalid} * <li/>exception with {@link SVNErrorCode#ENTRY_MISSING_URL} * error code - if failed to retrieve the repository url of * <code>path2</code> * </ul> * @since 1.2, SVN 1.5 */ public void doMerge(SVNURL url1, SVNRevision revision1, File path2, SVNRevision revision2, File dstPath, SVNDepth depth, boolean useAncestry, boolean force, boolean dryRun, boolean recordOnly) throws SVNException { path2 = path2.getAbsoluteFile(); dstPath = dstPath.getAbsoluteFile(); SVNURL url2 = getURL(path2); if (url2 == null) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.ENTRY_MISSING_URL, "''{0}'' has no URL", path2); SVNErrorManager.error(err, SVNLogType.WC); } runMerge(url1, revision1, url2, revision2, dstPath, depth, dryRun, force, !useAncestry, recordOnly); } /** * Applies the differences between two sources (one source URL against * another source URL) to a Working Copy path. * <p> * Corresponds to the SVN command line client's <code>'svn merge sourceURL1@rev1 sourceURL2@rev2 WCPATH'</code> command. * <p> * If you need only to try merging your file(s) without actual merging, you * should set <code>dryRun</code> to <span class="javakeyword">true</span>. * Your event handler will be dispatched status type information on the * target path(s). If a path can be successfully merged, the status type * will be {@link SVNStatusType#MERGED} for that path. * * @param url1 the * first source URL * @param revision1 a * revision of <code>url1</code> * @param url2 the * second source URL that is to be compared against * <code>url1</code> * @param revision2 a * revision of <code>url2</code> * @param dstPath the * target path to which the result should be applied * @param recursive * <span class="javakeyword">true</span> to descend recursively * @param useAncestry if * <span class="javakeyword">true</span> then the paths ancestry * will be noticed while calculating differences, otherwise not * @param force * <span class="javakeyword">true</span> to force the operation * to run * @param dryRun if * <span class="javakeyword">true</span> then only tries the * operation to run (to find out if a file can be merged * successfully) * @throws SVNException if * one of the following is true: * <ul> * <li>at least one of <code>revision1</code> and <code> * revision2</code> is invalid <li><code>url1</code> was not * found in <code>revision1</code> <li><code>url2</code> was not * found in <code>revision2</code> <li><code>dstPath</code> is * not under version control * </ul> * @deprecated use * {@link #doMerge(SVNURL,SVNRevision,SVNURL,SVNRevision,File,SVNDepth,boolean,boolean,boolean,boolean)} * instead */ public void doMerge(SVNURL url1, SVNRevision revision1, SVNURL url2, SVNRevision revision2, File dstPath, boolean recursive, boolean useAncestry, boolean force, boolean dryRun) throws SVNException { doMerge(url1, revision1, url2, revision2, dstPath, SVNDepth.getInfinityOrFilesDepth(recursive), useAncestry, force, dryRun, false); } /** * Merges changes from <code>url1</code>/<code>revision1</code> to * <code>url2</code>/<code>revision2</code> into the working-copy path * <code>dstPath</code>. * <p/> * <code>url1</code> and <code>url2</code> must both represent the same node * kind - that is, if <code>url1</code> is a directory, <code>url2</code> * must also be, and if <code>url1</code> is a file, <code>url2</code> must * also be. * <p/> * If <code>depth</code> is {@link SVNDepth#INFINITY}, merges fully * recursively. Else if {@link SVNDepth#IMMEDIATES}, merges changes at most * to files that are immediate children of <code>dstPath</code> and to * directory properties of <code>dstPath</code> and its immediate * subdirectory children. Else if {@link SVNDepth#FILES}, merges at most to * immediate file children of <code>dstPath</code> and to * <code>dstPath</code> itself. Else if {@link SVNDepth#EMPTY}, applies * changes only to <code>dstPath</code> (i.e., directory property changes * only). * <p/> * If <code>depth</code> is {@link SVNDepth#UNKNOWN}, uses the depth of * <code>dstPath</code>. * <p/> * Uses <code>useAncestry</code> to control whether or not items being * diffed will be checked for relatedness first. Unrelated items are * typically transmitted to the editor as a deletion of one thing and the * addition of another, but if this flag is <span * class="javakeyword">true</span>, unrelated items will be diffed as if * they were related. * <p/> * If <code>force</code> is not set and the merge involves deleting locally * modified or unversioned items the operation will fail. If * <code>force</code> is set such items will be deleted. * <p/> * {@link #getMergeOptions() merge options} is used to pass arguments to the * merge processes (internal or external). * <p/> * If the caller's {@link ISVNEventHandler} is not <span * class="javakeyword">null</span>, then it will be called once for each * merged target. * <p/> * If <code>recordOnly</code> is <span class="javakeyword">true</span>, the * merge isn't actually performed, but the mergeinfo for the revisions which * would've been merged is recorded in the working copy (and must be * subsequently committed back to the repository). * <p/> * If <code>dryRun</code> is <span class="javakeyword">true</span>, the * merge is carried out, and full notification feedback is provided, but the * working copy is not modified. * <p/> * Note: this method requires repository access. * * @param url1 left * -hand repository url * @param revision1 revision * of <code>url1</code> * @param url2 right * -hand repository url * @param revision2 revision * of <code>url2</code> * @param dstPath target * working copy path * @param depth tree * depth to process * @param useAncestry if * <span class="javakeyword">true</span> then the paths ancestry * will be noticed while calculating differences, otherwise not * @param force * <span class="javakeyword">true</span> to force the operation * to run * @param dryRun if * <span class="javakeyword">true</span> then runs merge without * any file changes * @param recordOnlyif * <span class="javakeyword">true</span>, records only the result * of merge - mergeinfo data * @throws SVNException in * the following cases: * <ul> * <li/>exception with {@link SVNErrorCode#CLIENT_BAD_REVISION} * error code - if either <code>revision1</code> or <code> * revision2</code> is {@link SVNRevision#isValid() invalid} * </ul> * @since 1.2, SVN 1.5 */ public void doMerge(SVNURL url1, SVNRevision revision1, SVNURL url2, SVNRevision revision2, File dstPath, SVNDepth depth, boolean useAncestry, boolean force, boolean dryRun, boolean recordOnly) throws SVNException { runMerge(url1, revision1, url2, revision2, dstPath, depth, dryRun, force, !useAncestry, recordOnly); } /** * Applies the differences between two sources (a source URL in a particular * revision against the same source URL in another particular revision) to a * Working Copy path. * <p> * Corresponds to the SVN command line client's <code>'svn merge -r rev1:rev2 URL@pegRev WCPATH'</code> command. * <p> * If you need only to try merging your file(s) without actual merging, you * should set <code>dryRun</code> to <span class="javakeyword">true</span>. * Your event handler will be dispatched status type information on the * target path(s). If a path can be successfully merged, the status type * will be {@link SVNStatusType#MERGED} for that path. * * @param url1 a * source URL * @param pegRevision a * revision in which code>url1</code> is first looked up * @param revision1 a * left-hand revision of <code>url1</code> * @param revision2 a * right-hand revision of <code>url1</code> * @param dstPath the * target path to which the result should be applied * @param recursive * <span class="javakeyword">true</span> to descend recursively * @param useAncestry if * <span class="javakeyword">true</span> then the paths ancestry * will be noticed while calculating differences, otherwise not * @param force * <span class="javakeyword">true</span> to force the operation * to run * @param dryRun if * <span class="javakeyword">true</span> then only tries the * operation to run (to find out if a file can be merged * successfully) * @throws SVNException if * one of the following is true: * <ul> * <li>at least one of <code>revision1</code>, <code>revision2 * </code> and <code>pegRevision</code> is invalid <li><code> * url1</code> was not found in <code>revision1</code> <li> * <code>url1</code> was not found in <code>revision2</code> * <li><code>dstPath</code> is not under version control * </ul> * @deprecated use * {@link #doMerge(SVNURL,SVNRevision,Collection,File,SVNDepth,boolean,boolean,boolean,boolean)} * instead */ public void doMerge(SVNURL url1, SVNRevision pegRevision, SVNRevision revision1, SVNRevision revision2, File dstPath, boolean recursive, boolean useAncestry, boolean force, boolean dryRun) throws SVNException { SVNRevisionRange range = new SVNRevisionRange(revision1, revision2); List rangesToMerge = new LinkedList(); rangesToMerge.add(range); doMerge(url1, pegRevision, rangesToMerge, dstPath, SVNDepth.getInfinityOrFilesDepth(recursive), useAncestry, force, dryRun, false); } /** * Merges the changes between <code>url1</code> in peg revision * <code>pegRevision</code>, as it changed between the ranges described in * <code>rangesToMerge</code>. * <p/> * <code>rangesToMerge</code> is a collection of {@link SVNRevisionRange} * ranges. These ranges may describe additive and/or subtractive merge * ranges, they may overlap fully or partially, and/or they may partially or * fully negate each other. This rangelist is not required to be sorted. * <p/> * All other options are handled identically to * {@link #doMerge(SVNURL,SVNRevision,SVNURL,SVNRevision,File,SVNDepth,boolean,boolean,boolean,boolean)}. * <p/> * Note: this method requires repository access. * * @param url1 a * source URL * @param pegRevision a * revision in which <code>url1</code> is first looked up * @param rangesToMergecollection * of revision ranges to merge * @param dstPath target * working copy path * @param depth tree * depth to process * @param useAncestry if * <span class="javakeyword">true</span> then the paths ancestry * will be noticed while calculating differences, otherwise not * @param force * <span class="javakeyword">true</span> to force the operation * to run * @param dryRun if * <span class="javakeyword">true</span> then only tries the * operation to run (to find out if a file can be merged * successfully) * @param recordOnly * @throws SVNException in * the following cases: * <ul> * <li/>exception with {@link SVNErrorCode#CLIENT_BAD_REVISION}- * If any revision in the list of provided ranges is * {@link SVNRevision#isValid() invalid} * </ul> * @since 1.2, SVN 1.5 */ public void doMerge(SVNURL url1, SVNRevision pegRevision, Collection rangesToMerge, File dstPath, SVNDepth depth, boolean useAncestry, boolean force, boolean dryRun, boolean recordOnly) throws SVNException { if (pegRevision == null || !pegRevision.isValid()) { pegRevision = SVNRevision.HEAD; } runPeggedMerge(url1, null, rangesToMerge, pegRevision, dstPath, depth, dryRun, force, !useAncestry, recordOnly); } /** * Applies the differences between two sources (the repository location of a * source Working Copy path in a particular revision against the repository * location of the same path in another particular revision) to a Working * Copy path. * <p> * Corresponds to the SVN command line client's <code>'svn merge -r rev1:rev2 sourceWCPATH@pegRev WCPATH'</code> command. * <p> * If you need only to try merging your file(s) without actual merging, you * should set <code>dryRun</code> to <span class="javakeyword">true</span>. * Your event handler will be dispatched status type information on the * target path(s). If a path can be successfully merged, the status type * will be {@link SVNStatusType#MERGED} for that path. * * @param path1 a * source WC path * @param pegRevision a * revision in which the repository location of * <code>path1</code> is first looked up * @param revision1 a * left-hand revision of <code>path1</code> * @param revision2 a * right-hand revision of <code>path1</code> * @param dstPath the * target path to which the result should be applied * @param recursive * <span class="javakeyword">true</span> to descend recursively * @param useAncestry if * <span class="javakeyword">true</span> then the paths ancestry * will be noticed while calculating differences, otherwise not * @param force * <span class="javakeyword">true</span> to force the operation * to run * @param dryRun if * <span class="javakeyword">true</span> then only tries the * operation to run (to find out if a file can be merged * successfully) * @throws SVNException if * one of the following is true: * <ul> * <li>at least one of <code>revision1</code>, <code>revision2 * </code> and <code>pegRevision</code> is invalid <li><code> * path1</code> has no URL <li>the repository location of <code> * path1</code> was not found in <code>revision1</code> <li>the * repository location of <code>path1</code> was not found in * <code>revision2</code> <li><code>dstPath</code> is not under * version control * </ul> * @deprecated use * {@link #doMerge(File,SVNRevision,Collection,File,SVNDepth,boolean,boolean,boolean,boolean)} * instead */ public void doMerge(File path1, SVNRevision pegRevision, SVNRevision revision1, SVNRevision revision2, File dstPath, boolean recursive, boolean useAncestry, boolean force, boolean dryRun) throws SVNException { SVNRevisionRange range = new SVNRevisionRange(revision1, revision2); List rangesToMerge = new LinkedList(); rangesToMerge.add(range); doMerge(path1, pegRevision, rangesToMerge, dstPath, SVNDepth.getInfinityOrFilesDepth(recursive), useAncestry, force, dryRun, false); } /** * Merges the changes between <code>path1</code> in peg revision * <code>pegRevision</code>, as it changed between the ranges described in * <code>rangesToMerge</code>. * <p/> * <code>rangesToMerge</code> is a collection of {@link SVNRevisionRange} * ranges. These ranges may describe additive and/or subtractive merge * ranges, they may overlap fully or partially, and/or they may partially or * fully negate each other. This rangelist is not required to be sorted. * <p/> * All other options are handled identically to * {@link #doMerge(File,SVNRevision,File,SVNRevision,File,SVNDepth,boolean,boolean,boolean,boolean)}. * <p/> * Note: this method requires repository access. * * @param path1 working * copy path * @param pegRevision a * revision in which <code>path1</code> is first looked up * @param rangesToMergecollection * of revision ranges to merge * @param dstPath target * working copy path * @param depth tree * depth to process * @param useAncestry if * <span class="javakeyword">true</span> then the paths ancestry * will be noticed while calculating differences, otherwise not * @param force * <span class="javakeyword">true</span> to force the operation * to run * @param dryRun if * <span class="javakeyword">true</span> then only tries the * operation to run (to find out if a file can be merged * successfully) * @param recordOnly * @throws SVNException in * the following cases: * <ul> * <li/>exception with {@link SVNErrorCode#CLIENT_BAD_REVISION}- * If any revision in the list of provided ranges is * {@link SVNRevision#isValid() invalid} * </ul> * @since 1.2, SVN 1.5 */ public void doMerge(File path1, SVNRevision pegRevision, Collection rangesToMerge, File dstPath, SVNDepth depth, boolean useAncestry, boolean force, boolean dryRun, boolean recordOnly) throws SVNException { if (pegRevision == null || !pegRevision.isValid()) { pegRevision = SVNRevision.WORKING; } runPeggedMerge(null, path1, rangesToMerge, pegRevision, dstPath, depth, dryRun, force, !useAncestry, recordOnly); } /** * Performs a reintegration merge of <code>srcPath</code> at * <code>pegRevision</code> into <code>dstPath</code>. * <p/> * <code>dstPath</code> must be a single-revision, {@link SVNDepth#INFINITY} * , pristine, unswitched working copy -- in other words, it must reflect a * single revision tree, the "target". The mergeinfo on <code>srcPath</code> * must reflect that all of the target has been merged into it. * <p/> * This kind of merge should be used for back merging (for example, merging * branches back to trunk, in which case merge is carried out by comparing * the latest trunk tree with the latest branch tree; i.e. the resulting * difference is excatly the branch changes which will go back to trunk). * <p/> * All other options are handled identically to * {@link #doMerge(File,SVNRevision,File,SVNRevision,File,SVNDepth,boolean,boolean,boolean,boolean)} * . The depth of the merge is always {@link SVNDepth#INFINITY}. * <p/> * If <code>pegRevision</code> is <span class="javakeyword">null</span> or * {@link SVNRevision#isValid() invalid}, then it defaults to * {@link SVNRevision#WORKING}. * <p/> * Note: this method requires repository access. * * @param srcPath working * copy path * @param pegRevision a * revision in which <code>srcPath</code> is first looked up * @param dstPath target * working copy path * @param dryRun if * <span class="javakeyword">true</span> then only tries the * operation to run (to find out if a file can be merged * successfully) * @throws SVNException * @since 1.2, SVN 1.5 */ public void doMergeReIntegrate(File srcPath, SVNRevision pegRevision, File dstPath, boolean dryRun) throws SVNException { if (pegRevision == null || !pegRevision.isValid()) { pegRevision = SVNRevision.WORKING; } runMergeReintegrate(null, srcPath, pegRevision, dstPath, dryRun); } /** * Performs a reintegration merge of <code>srcURL</code> at * <code>pegRevision</code> into <code>dstPath</code>. * <p/> * <code>dstPath</code> must be a single-revision, {@link SVNDepth#INFINITY} * , pristine, unswitched working copy -- in other words, it must reflect a * single revision tree, the "target". The mergeinfo on <code>srcPath</code> * must reflect that all of the target has been merged into it. * <p/> * This kind of merge should be used for back merging (for example, merging * branches back to trunk, in which case merge is carried out by comparing * the latest trunk tree with the latest branch tree; i.e. the resulting * difference is excatly the branch changes which will go back to trunk). * <p/> * All other options are handled identically to * {@link #doMerge(SVNURL,SVNRevision,SVNURL,SVNRevision,File,SVNDepth,boolean,boolean,boolean,boolean)} * . The depth of the merge is always {@link SVNDepth#INFINITY}. * <p/> * If <code>pegRevision</code> is <span class="javakeyword">null</span> or * {@link SVNRevision#isValid() invalid}, then it defaults to * {@link SVNRevision#HEAD}. * <p/> * Note: this method requires repository access. * * @param srcURL repository * url * @param pegRevision a * revision in which <code>srcURL</code> is first looked up * @param dstPath target * working copy path * @param dryRun if * <span class="javakeyword">true</span> then only tries the * operation to run (to find out if a file can be merged * successfully) * @throws SVNException * @since 1.2, SVN 1.5 */ public void doMergeReIntegrate(SVNURL srcURL, SVNRevision pegRevision, File dstPath, boolean dryRun) throws SVNException { if (pegRevision == null || !pegRevision.isValid()) { pegRevision = SVNRevision.HEAD; } runMergeReintegrate(srcURL, null, pegRevision, dstPath, dryRun); } /** * Drives a log entry <code>handler</code> with the revisions merged from * <code>mergeSrcURL</code> (as of <code>srcPegRevision</code>) into * <code>path</code> (as of <code>pegRevision</code>). * <p/> * <code>discoverChangedPaths</code> and <code>revisionProperties</code> are * the same as for * {@link SVNLogClient#doLog(File[],SVNRevision,SVNRevision,SVNRevision,boolean,boolean,boolean,long,String[],ISVNLogEntryHandler)}. * <p/> * Note: this routine requires repository access. * * @param pathworking * copy path (merge target) * @param pegRevision a * revision in which <code>path</code> is first looked up * @param mergeSrcURLmerge * source repository url * @param srcpegRevision a * revision in which <code>mergeSrcURL</code> is first looked up * @param discoverChangedPaths * <span class="javakeyword">true</span> to report of all changed * paths for every revision being processed (those paths will be * available by calling * {@link org.tmatesoft.svn.core.SVNLogEntry#getChangedPaths()}) * @param revisionPropertiesnames * of revision properties to retrieve * @param handlerthe * caller's log entry handler * @throws SVNException in * the following cases: * <ul> * <li/>exception with {@link SVNErrorCode#UNSUPPORTED_FEATURE} * error code - if the server doesn't support retrieval of * mergeinfo * </ul> * @since 1.2, SVN 1.5 */ public void doGetLogMergedMergeInfo(File path, SVNRevision pegRevision, SVNURL mergeSrcURL, SVNRevision srcPegRevision, boolean discoverChangedPaths, String[] revisionProperties, ISVNLogEntryHandler handler) throws SVNException { getLogMergedMergeInfoImpl(path, null, pegRevision, mergeSrcURL, null, srcPegRevision, discoverChangedPaths, revisionProperties, handler); } /** * Drives a log entry <code>handler</code> with the revisions merged from * <code>mergeSrcURL</code> (as of <code>srcPegRevision</code>) into * <code>url</code> (as of <code>pegRevision</code>). * <p/> * <code>discoverChangedPaths</code> and <code>revisionProperties</code> are * the same as for * {@link SVNLogClient#doLog(File[],SVNRevision,SVNRevision,SVNRevision,boolean,boolean,boolean,long,String[],ISVNLogEntryHandler)}. * <p/> * Note: this routine requires repository access. * * @param urlrepository * url (merge target) * @param pegRevision a * revision in which <code>url</code> is first looked up * @param mergeSrcURLmerge * source repository url * @param srcpegRevision a * revision in which <code>mergeSrcURL</code> is first looked up * @param discoverChangedPaths * <span class="javakeyword">true</span> to report of all changed * paths for every revision being processed (those paths will be * available by calling * {@link org.tmatesoft.svn.core.SVNLogEntry#getChangedPaths()}) * @param revisionPropertiesnames * of revision properties to retrieve * @param handlerthe * caller's log entry handler * @throws SVNException in * the following cases: * <ul> * <li/>exception with {@link SVNErrorCode#UNSUPPORTED_FEATURE} * error code - if the server doesn't support retrieval of * mergeinfo * </ul> * @since 1.2, SVN 1.5 */ public void doGetLogMergedMergeInfo(SVNURL url, SVNRevision pegRevision, SVNURL mergeSrcURL, SVNRevision srcPegRevision, boolean discoverChangedPaths, String[] revisionProperties, ISVNLogEntryHandler handler) throws SVNException { getLogMergedMergeInfoImpl(null, url, pegRevision, mergeSrcURL, null, srcPegRevision, discoverChangedPaths, revisionProperties, handler); } /** * Drives a log entry <code>handler</code> with the revisions merged from * <code>mergeSrcPath</code> (as of <code>srcPegRevision</code>) into * <code>path</code> (as of <code>pegRevision</code>). * <p/> * <code>discoverChangedPaths</code> and <code>revisionProperties</code> are * the same as for * {@link SVNLogClient#doLog(File[],SVNRevision,SVNRevision,SVNRevision,boolean,boolean,boolean,long,String[],ISVNLogEntryHandler)}. * <p/> * Note: this routine requires repository access. * * @param pathworking * copy path (merge target) * @param pegRevision a * revision in which <code>path</code> is first looked up * @param mergeSrcPathmerge * source working copy path * @param srcpegRevision a * revision in which <code>mergeSrcPath</code> is first looked up * @param discoverChangedPaths * <span class="javakeyword">true</span> to report of all changed * paths for every revision being processed (those paths will be * available by calling * {@link org.tmatesoft.svn.core.SVNLogEntry#getChangedPaths()}) * @param revisionPropertiesnames * of revision properties to retrieve * @param handlerthe * caller's log entry handler * @throws SVNException in * the following cases: * <ul> * <li/>exception with {@link SVNErrorCode#UNSUPPORTED_FEATURE} * error code - if the server doesn't support retrieval of * mergeinfo * </ul> * @since 1.2, SVN 1.5 */ public void doGetLogMergedMergeInfo(File path, SVNRevision pegRevision, File mergeSrcPath, SVNRevision srcPegRevision, boolean discoverChangedPaths, String[] revisionProperties, ISVNLogEntryHandler handler) throws SVNException { getLogMergedMergeInfoImpl(path, null, pegRevision, null, mergeSrcPath, srcPegRevision, discoverChangedPaths, revisionProperties, handler); } /** * Drives a log entry <code>handler</code> with the revisions merged from * <code>mergeSrcPath</code> (as of <code>srcPegRevision</code>) into * <code>url</code> (as of <code>pegRevision</code>). * <p/> * <code>discoverChangedPaths</code> and <code>revisionProperties</code> are * the same as for * {@link SVNLogClient#doLog(File[],SVNRevision,SVNRevision,SVNRevision,boolean,boolean,boolean,long,String[],ISVNLogEntryHandler)}. * <p/> * Note: this routine requires repository access. * * @param urlrepository * url (merge target) * @param pegRevision a * revision in which <code>url</code> is first looked up * @param mergeSrcPathmerge * source working copy path * @param srcpegRevision a * revision in which <code>mergeSrcPath</code> is first looked up * @param discoverChangedPaths * <span class="javakeyword">true</span> to report of all changed * paths for every revision being processed (those paths will be * available by calling * {@link org.tmatesoft.svn.core.SVNLogEntry#getChangedPaths()}) * @param revisionPropertiesnames * of revision properties to retrieve * @param handlerthe * caller's log entry handler * @throws SVNException in * the following cases: * <ul> * <li/>exception with {@link SVNErrorCode#UNSUPPORTED_FEATURE} * error code - if the server doesn't support retrieval of * mergeinfo * </ul> * @since 1.2, SVN 1.5 */ public void doGetLogMergedMergeInfo(SVNURL url, SVNRevision pegRevision, File mergeSrcPath, SVNRevision srcPegRevision, boolean discoverChangedPaths, String[] revisionProperties, ISVNLogEntryHandler handler) throws SVNException { getLogMergedMergeInfoImpl(null, url, pegRevision, null, mergeSrcPath, srcPegRevision, discoverChangedPaths, revisionProperties, handler); } /** * Drives a log entry <code>handler</code> with the revisions eligible for * merge from <code>mergeSrcURL</code> (as of <code>srcPegRevision</code>) * into <code>path</code> (as of <code>pegRevision</code>). * <p/> * <code>discoverChangedPaths</code> and <code>revisionProperties</code> are * the same as for * {@link SVNLogClient#doLog(File[],SVNRevision,SVNRevision,SVNRevision,boolean,boolean,boolean,long,String[],ISVNLogEntryHandler)}. * <p/> * Note: this routine requires repository access. * * @param pathworking * copy path (merge target) * @param pegRevision a * revision in which <code>path</code> is first looked up * @param mergeSrcURLmerge * source repository url * @param srcpegRevision a * revision in which <code>mergeSrcURL</code> is first looked up * @param discoverChangedPaths * <span class="javakeyword">true</span> to report of all changed * paths for every revision being processed (those paths will be * available by calling * {@link org.tmatesoft.svn.core.SVNLogEntry#getChangedPaths()}) * @param revisionPropertiesnames * of revision properties to retrieve * @param handlerthe * caller's log entry handler * @throws SVNException in * the following cases: * <ul> * <li/>exception with {@link SVNErrorCode#UNSUPPORTED_FEATURE} * error code - if the server doesn't support retrieval of * mergeinfo * </ul> * @since 1.2, SVN 1.5 */ public void doGetLogEligibleMergeInfo(File path, SVNRevision pegRevision, SVNURL mergeSrcURL, SVNRevision srcPegRevision, boolean discoverChangedPaths, String[] revisionProperties, ISVNLogEntryHandler handler) throws SVNException { getLogEligibleMergeInfoImpl(path, null, pegRevision, mergeSrcURL, null, srcPegRevision, discoverChangedPaths, revisionProperties, handler); } /** * Drives a log entry <code>handler</code> with the revisions eligible for * merge from <code>mergeSrcURL</code> (as of <code>srcPegRevision</code>) * into <code>url</code> (as of <code>pegRevision</code>). * <p/> * <code>discoverChangedPaths</code> and <code>revisionProperties</code> are * the same as for * {@link SVNLogClient#doLog(File[],SVNRevision,SVNRevision,SVNRevision,boolean,boolean,boolean,long,String[],ISVNLogEntryHandler)}. * <p/> * Note: this routine requires repository access. * * @param urlrepository * url (merge target) * @param pegRevision a * revision in which <code>url</code> is first looked up * @param mergeSrcURLmerge * source repository url * @param srcpegRevision a * revision in which <code>mergeSrcURL</code> is first looked up * @param discoverChangedPaths * <span class="javakeyword">true</span> to report of all changed * paths for every revision being processed (those paths will be * available by calling * {@link org.tmatesoft.svn.core.SVNLogEntry#getChangedPaths()}) * @param revisionPropertiesnames * of revision properties to retrieve * @param handlerthe * caller's log entry handler * @throws SVNException in * the following cases: * <ul> * <li/>exception with {@link SVNErrorCode#UNSUPPORTED_FEATURE} * error code - if the server doesn't support retrieval of * mergeinfo * </ul> * @since 1.2, SVN 1.5 */ public void doGetLogEligibleMergeInfo(SVNURL url, SVNRevision pegRevision, SVNURL mergeSrcURL, SVNRevision srcPegRevision, boolean discoverChangedPaths, String[] revisionProperties, ISVNLogEntryHandler handler) throws SVNException { getLogEligibleMergeInfoImpl(null, url, pegRevision, mergeSrcURL, null, srcPegRevision, discoverChangedPaths, revisionProperties, handler); } /** * Drives a log entry <code>handler</code> with the revisions eligible for * merge from <code>mergeSrcPath</code> (as of <code>srcPegRevision</code>) * into <code>path</code> (as of <code>pegRevision</code>). * <p/> * <code>discoverChangedPaths</code> and <code>revisionProperties</code> are * the same as for * {@link SVNLogClient#doLog(File[],SVNRevision,SVNRevision,SVNRevision,boolean,boolean,boolean,long,String[],ISVNLogEntryHandler)}. * <p/> * Note: this routine requires repository access. * * @param pathworking * copy path (merge target) * @param pegRevision a * revision in which <code>path</code> is first looked up * @param mergeSrcPathmerge * source working copy path * @param srcpegRevision a * revision in which <code>mergeSrcPath</code> is first looked up * @param discoverChangedPaths * <span class="javakeyword">true</span> to report of all changed * paths for every revision being processed (those paths will be * available by calling * {@link org.tmatesoft.svn.core.SVNLogEntry#getChangedPaths()}) * @param revisionPropertiesnames * of revision properties to retrieve * @param handlerthe * caller's log entry handler * @throws SVNException in * the following cases: * <ul> * <li/>exception with {@link SVNErrorCode#UNSUPPORTED_FEATURE} * error code - if the server doesn't support retrieval of * mergeinfo * </ul> * @since 1.2, SVN 1.5 */ public void doGetLogEligibleMergeInfo(File path, SVNRevision pegRevision, File mergeSrcPath, SVNRevision srcPegRevision, boolean discoverChangedPaths, String[] revisionProperties, ISVNLogEntryHandler handler) throws SVNException { getLogEligibleMergeInfoImpl(path, null, pegRevision, null, mergeSrcPath, srcPegRevision, discoverChangedPaths, revisionProperties, handler); } /** * Drives a log entry <code>handler</code> with the revisions eligible for * merge from <code>mergeSrcPath</code> (as of <code>srcPegRevision</code>) * into <code>url</code> (as of <code>pegRevision</code>). * <p/> * <code>discoverChangedPaths</code> and <code>revisionProperties</code> are * the same as for * {@link SVNLogClient#doLog(File[],SVNRevision,SVNRevision,SVNRevision,boolean,boolean,boolean,long,String[],ISVNLogEntryHandler)}. * <p/> * Note: this routine requires repository access. * * @param urlrepository * url (merge target) * @param pegRevision a * revision in which <code>url</code> is first looked up * @param mergeSrcPathmerge * source working copy path * @param srcpegRevision a * revision in which <code>mergeSrcPath</code> is first looked up * @param discoverChangedPaths * <span class="javakeyword">true</span> to report of all changed * paths for every revision being processed (those paths will be * available by calling * {@link org.tmatesoft.svn.core.SVNLogEntry#getChangedPaths()}) * @param revisionPropertiesnames * of revision properties to retrieve * @param handlerthe * caller's log entry handler * @throws SVNException in * the following cases: * <ul> * <li/>exception with {@link SVNErrorCode#UNSUPPORTED_FEATURE} * error code - if the server doesn't support retrieval of * mergeinfo * </ul> * @since 1.2, SVN 1.5 */ public void doGetLogEligibleMergeInfo(SVNURL url, SVNRevision pegRevision, File mergeSrcPath, SVNRevision srcPegRevision, boolean discoverChangedPaths, String[] revisionProperties, ISVNLogEntryHandler handler) throws SVNException { getLogEligibleMergeInfoImpl(null, url, pegRevision, null, mergeSrcPath, srcPegRevision, discoverChangedPaths, revisionProperties, handler); } /** * Returns mergeinfo as a <code>Map</code> with merge source URLs (as * {@link SVNURL}) mapped to range lists ({@link SVNMergeRangeList}). Range * lists are objects containing arrays of {@link SVNMergeRange ranges} * describing the ranges which have been merged into <code>path</code> as of * <code>pegRevision</code>. If there is no mergeinfo, returns <span * class="javakeyword">null</span>. * <p/> * Note: unlike most APIs which deal with mergeinfo, this one returns data * where the keys of the map are absolute repository URLs rather than * repository filesystem paths. * <p/> * Note: this routine requires repository access. * * @param pathworking * copy path * @param pegRevision a * revision in which <code>path</code> is first looked up * @return mergeinfo for <code>path</code> * @throws SVNException in * the following cases: * <ul> * <li/>exception with {@link SVNErrorCode#UNSUPPORTED_FEATURE} * error code - if the server doesn't support retrieval of * mergeinfo (which will never happen for file:// URLs) * </ul> * @since 1.2, SVN 1.5 */ public Map<SVNURL, SVNMergeRangeList> doGetMergedMergeInfo(File path, SVNRevision pegRevision) throws SVNException { SVNURL reposRoot[] = new SVNURL[1]; Map mergeInfo = getMergeInfo(path, pegRevision, reposRoot); SVNURL repositoryRoot = reposRoot[0]; if (mergeInfo != null) { Map<SVNURL, SVNMergeRangeList> fullPathMergeInfo = new TreeMap<SVNURL, SVNMergeRangeList>(new Comparator<SVNURL>() { public int compare(SVNURL o1, SVNURL o2) { return o1.toString().compareTo(o2.toString()); } }); for (Iterator paths = mergeInfo.keySet().iterator(); paths.hasNext();) { String mergeSrcPath = (String) paths.next(); SVNMergeRangeList rangeList = (SVNMergeRangeList) mergeInfo.get(mergeSrcPath); if (mergeSrcPath.startsWith("/")) { mergeSrcPath = mergeSrcPath.substring(1); } SVNURL url = repositoryRoot.appendPath(mergeSrcPath, false); fullPathMergeInfo.put(url, rangeList); } mergeInfo = fullPathMergeInfo; } return mergeInfo; } /** * Returns mergeinfo as a <code>Map</code> with merge source URLs (as * {@link SVNURL}) mapped to range lists ({@link SVNMergeRangeList}). Range * lists are objects containing arrays of {@link SVNMergeRange ranges} * describing the ranges which have been merged into <code>url</code> as of * <code>pegRevision</code>. If there is no mergeinfo, returns <span * class="javakeyword">null</span>. * <p/> * Note: unlike most APIs which deal with mergeinfo, this one returns data * where the keys of the map are absolute repository URLs rather than * repository filesystem paths. * <p/> * Note: this routine requires repository access. * * @param urlrepository * url * @param pegRevision a * revision in which <code>url</code> is first looked up * @return mergeinfo for <code>url</code> * @throws SVNException in * the following cases: * <ul> * <li/>exception with {@link SVNErrorCode#UNSUPPORTED_FEATURE} * error code - if the server doesn't support retrieval of * mergeinfo (which will never happen for file:// URLs) * </ul> * @since 1.2, SVN 1.5 */ public Map<SVNURL, SVNMergeRangeList> doGetMergedMergeInfo(SVNURL url, SVNRevision pegRevision) throws SVNException { SVNURL reposRoot[] = new SVNURL[1]; Map mergeInfo = getMergeInfo(url, pegRevision, reposRoot); SVNURL repositoryRoot = reposRoot[0]; if (mergeInfo != null) { Map<SVNURL, SVNMergeRangeList> fullPathMergeInfo = new TreeMap<SVNURL, SVNMergeRangeList>(new Comparator<SVNURL>() { public int compare(SVNURL o1, SVNURL o2) { return o1.toString().compareTo(o2.toString()); } }); for (Iterator paths = mergeInfo.keySet().iterator(); paths.hasNext();) { String mergeSrcPath = (String) paths.next(); SVNMergeRangeList rangeList = (SVNMergeRangeList) mergeInfo.get(mergeSrcPath); if (mergeSrcPath.startsWith("/")) { mergeSrcPath = mergeSrcPath.substring(1); } SVNURL nextURL = repositoryRoot.appendPath(mergeSrcPath, false); fullPathMergeInfo.put(nextURL, rangeList); } mergeInfo = fullPathMergeInfo; } return mergeInfo; } /** * Returns a collection of potential merge sources (expressed as full * repository {@link SVNURL URLs}) for <code>path</code> at * <code>pegRevision</code>. * * @param pathworking * copy path * @param pegRevision a * revision in which <code>path</code> is first looked up * @throws SVNException * @return potential merge sources for <code>path</code> * @since 1.2, SVN 1.5 */ public Collection<SVNURL> doSuggestMergeSources(File path, SVNRevision pegRevision) throws SVNException { LinkedList<SVNURL> suggestions = new LinkedList<SVNURL>(); SVNURL reposRoot = getReposRoot(path, null, pegRevision, null, null); SVNLocationEntry copyFromInfo = getCopySource(path, null, pegRevision); String copyFromPath = copyFromInfo.getPath(); SVNURL copyFromURL = null; if (copyFromPath != null) { String relCopyFromPath = copyFromPath.startsWith("/") ? copyFromPath.substring(1) : copyFromPath; copyFromURL = reposRoot.appendPath(relCopyFromPath, false); suggestions.add(copyFromURL); } Map mergeInfo = doGetMergedMergeInfo(path, pegRevision); if (mergeInfo != null) { for (Iterator mergeSrcURLs = mergeInfo.keySet().iterator(); mergeSrcURLs.hasNext();) { SVNURL mergeSrcURL = (SVNURL) mergeSrcURLs.next(); if (copyFromURL == null || !copyFromURL.equals(mergeSrcURL)) { suggestions.add(mergeSrcURL); } } } return suggestions; } /** * Returns a collection of potential merge sources (expressed as full * repository {@link SVNURL URLs}) for <code>url</code> at * <code>pegRevision</code>. * * @param urlrepository * url * @param pegRevision a * revision in which <code>url</code> is first looked up * @throws SVNException * @return potential merge sources for <code>url</code> * @since 1.2, SVN 1.5 */ public Collection<SVNURL> doSuggestMergeSources(SVNURL url, SVNRevision pegRevision) throws SVNException { LinkedList<SVNURL> suggestions = new LinkedList<SVNURL>(); SVNURL reposRoot = getReposRoot(null, url, pegRevision, null, null); SVNLocationEntry copyFromInfo = getCopySource(null, url, pegRevision); String copyFromPath = copyFromInfo.getPath(); SVNURL copyFromURL = null; if (copyFromPath != null) { String relCopyFromPath = copyFromPath.startsWith("/") ? copyFromPath.substring(1) : copyFromPath; copyFromURL = reposRoot.appendPath(relCopyFromPath, false); suggestions.add(copyFromURL); } Map mergeInfo = doGetMergedMergeInfo(url, pegRevision); if (mergeInfo != null) { for (Iterator mergeSrcURLs = mergeInfo.keySet().iterator(); mergeSrcURLs.hasNext();) { SVNURL mergeSrcURL = (SVNURL) mergeSrcURLs.next(); if (copyFromURL == null || !copyFromURL.equals(mergeSrcURL)) { suggestions.add(mergeSrcURL); } } } return suggestions; } private void doDiffURLWC(SVNURL url1, SVNRevision revision1, SVNRevision pegRevision, File path2, SVNRevision revision2, boolean reverse, SVNDepth depth, boolean useAncestry, OutputStream result, Collection changeLists) throws SVNException { SVNWCAccess wcAccess = createWCAccess(); try { SVNAdminAreaInfo info = wcAccess.openAnchor(path2, false, SVNDepth.recurseFromDepth(depth) ? SVNWCAccess.INFINITE_DEPTH : 0); File anchorPath = info.getAnchor().getRoot(); String target = "".equals(info.getTargetName()) ? null : info.getTargetName(); SVNEntry anchorEntry = info.getAnchor().getVersionedEntry("", false); if (anchorEntry.getURL() == null) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.ENTRY_MISSING_URL, "''{0}'' has no URL", anchorPath); SVNErrorManager.error(err, SVNLogType.WC); } SVNURL anchorURL = anchorEntry.getSVNURL(); if (pegRevision.isValid()) { SVNRepositoryLocation[] locations = getLocations(url1, null, null, pegRevision, revision1, SVNRevision.UNDEFINED); url1 = locations[0].getURL(); String anchorPath2 = SVNPathUtil.append(anchorURL.toString(), target == null ? "" : target); getDiffGenerator().init(url1.toString(), anchorPath2); } SVNRepository repository = createRepository(anchorURL, null, null, true); long revNumber = getRevisionNumber(revision1, repository, null); AbstractDiffCallback callback = new SVNDiffCallback(info.getAnchor(), getDiffGenerator(), reverse ? -1 : revNumber, reverse ? revNumber : -1, result); SVNDiffEditor editor = new SVNDiffEditor(wcAccess, info, callback, useAncestry, reverse, revision2 == SVNRevision.BASE || revision2 == SVNRevision.COMMITTED, depth, changeLists); boolean serverSupportsDepth = repository.hasCapability(SVNCapability.DEPTH); SVNReporter reporter = new SVNReporter(info, info.getAnchor().getFile(info.getTargetName()), false, !serverSupportsDepth, depth, false, false, true, getDebugLog()); long pegRevisionNumber = getRevisionNumber(revision2, repository, path2); try { repository.diff(url1, revNumber, pegRevisionNumber, target, !useAncestry, depth, true, reporter, SVNCancellableEditor.newInstance(editor, this, getDebugLog())); } finally { editor.cleanup(); } } finally { wcAccess.close(); } } private void doDiffURLWC(File path1, SVNRevision revision1, SVNRevision pegRevision, File path2, SVNRevision revision2, boolean reverse, SVNDepth depth, boolean useAncestry, OutputStream result, Collection changeLists) throws SVNException { SVNWCAccess wcAccess = createWCAccess(); try { int admDepth = getAdminDepth(depth); SVNAdminAreaInfo info = wcAccess.openAnchor(path2, false, admDepth); File anchorPath = info.getAnchor().getRoot(); String target = "".equals(info.getTargetName()) ? null : info.getTargetName(); SVNEntry anchorEntry = info.getAnchor().getVersionedEntry("", false); if (anchorEntry.getURL() == null) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.ENTRY_MISSING_URL, "''{0}'' has no URL", anchorPath); SVNErrorManager.error(err, SVNLogType.WC); } SVNURL url1; SVNURL anchorURL = anchorEntry.getSVNURL(); if (pegRevision.isValid()) { SVNRepositoryLocation[] locations = getLocations(null, path1, null, pegRevision, revision1, SVNRevision.UNDEFINED); url1 = locations[0].getURL(); String anchorPath2 = SVNPathUtil.append(anchorURL.toString(), target == null ? "" : target); if (!reverse) { getDiffGenerator().init(url1.toString(), anchorPath2); } else { getDiffGenerator().init(anchorPath2, url1.toString()); } } else { url1 = getURL(path1); } SVNRepository repository = createRepository(anchorURL, null, null, true); long revNumber = getRevisionNumber(revision1, repository, path1); AbstractDiffCallback callback = new SVNDiffCallback(info.getAnchor(), getDiffGenerator(), reverse ? -1 : revNumber, reverse ? revNumber : -1, result); SVNDiffEditor editor = new SVNDiffEditor(wcAccess, info, callback, useAncestry, reverse, revision2 == SVNRevision.BASE || revision2 == SVNRevision.COMMITTED, depth, changeLists); ISVNEditor filterEditor = SVNAmbientDepthFilterEditor.wrap(editor, info, false); boolean serverSupportsDepth = repository.hasCapability(SVNCapability.DEPTH); SVNReporter reporter = new SVNReporter(info, info.getAnchor().getFile(info.getTargetName()), false, !serverSupportsDepth, depth, false, false, true, getDebugLog()); long pegRevisionNumber = getRevisionNumber(revision2, repository, path2); try { repository.diff(url1, revNumber, pegRevisionNumber, target, !useAncestry, depth, true, reporter, SVNCancellableEditor.newInstance(filterEditor, this, getDebugLog())); } finally { editor.cleanup(); } } finally { wcAccess.close(); } } private void doDiffWCWC(File path1, SVNRevision revision1, File path2, SVNRevision revision2, SVNDepth depth, boolean useAncestry, OutputStream result, Collection changeLists) throws SVNException { if (!path1.equals(path2) || !(revision1 == SVNRevision.BASE && revision2 == SVNRevision.WORKING)) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.UNSUPPORTED_FEATURE, "Only diffs between a path's text-base and its working files are supported at this time (-rBASE:WORKING)"); SVNErrorManager.error(err, SVNLogType.WC); } SVNWCAccess wcAccess = createWCAccess(); try { int admDepth = getAdminDepth(depth); SVNAdminAreaInfo info = wcAccess.openAnchor(path1, false, admDepth); wcAccess.getVersionedEntry(path1, false); long rev = getRevisionNumber(revision1, null, path1); AbstractDiffCallback callback = new SVNDiffCallback(info.getAnchor(), getDiffGenerator(), rev, -1, result); SVNDiffEditor editor = new SVNDiffEditor(wcAccess, info, callback, useAncestry, false, false, depth, changeLists); try { editor.closeEdit(); } finally { editor.cleanup(); } } finally { wcAccess.close(); } } private void doDiffURLURL(SVNURL url1, File path1, SVNRevision revision1, SVNURL url2, File path2, SVNRevision revision2, SVNRevision pegRevision, SVNDepth depth, boolean useAncestry, OutputStream result) throws SVNException { File basePath = null; if (path1 != null) { basePath = path1; } if (path2 != null) { basePath = path2; } if (pegRevision.isValid()) { SVNRepositoryLocation[] locations = getLocations(url2, path2, null, pegRevision, revision1, revision2); url1 = locations[0].getURL(); url2 = locations[1].getURL(); getDiffGenerator().init(url1.toString(), url2.toString()); } else { url1 = url1 == null ? getURL(path1) : url1; url2 = url2 == null ? getURL(path2) : url2; } SVNRepository repository1 = createRepository(url1, null, null, true); SVNRepository repository2 = createRepository(url2, null, null, false); final long rev1 = getRevisionNumber(revision1, repository1, path1); long rev2 = -1; String target1 = null; SVNNodeKind kind1 = null; SVNNodeKind kind2 = null; try { rev2 = getRevisionNumber(revision2, repository2, path2); kind1 = repository1.checkPath("", rev1); kind2 = repository2.checkPath("", rev2); if (kind1 == SVNNodeKind.NONE) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.FS_NOT_FOUND, "''{0}'' was not found in the repository at revision {1}", new Object[] { url1, new Long(rev1) }); SVNErrorManager.error(err, SVNLogType.WC); } else if (kind2 == SVNNodeKind.NONE) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.FS_NOT_FOUND, "''{0}'' was not found in the repository at revision {1}", new Object[] { url2, new Long(rev2) }); SVNErrorManager.error(err, SVNLogType.WC); } } finally { repository2.closeSession(); } if (kind1 == SVNNodeKind.FILE || kind2 == SVNNodeKind.FILE) { target1 = SVNPathUtil.tail(url1.getPath()); if (basePath != null) { basePath = basePath.getParentFile(); } url1 = SVNURL.parseURIEncoded(SVNPathUtil.removeTail(url1.toString())); repository1 = createRepository(url1, null, null, true); } repository2 = createRepository(url1, null, null, false); SVNRemoteDiffEditor editor = null; try { SVNDiffCallback callback = new SVNDiffCallback(null, getDiffGenerator(), rev1, rev2, result); callback.setBasePath(basePath); editor = new SVNRemoteDiffEditor(null, null, callback, repository2, rev1, rev2, false, null, this); editor.setUseGlobalTmp(true); ISVNReporterBaton reporter = new ISVNReporterBaton() { public void report(ISVNReporter reporter) throws SVNException { reporter.setPath("", null, rev1, SVNDepth.INFINITY, false); reporter.finishReport(); } }; repository1.diff(url2, rev2, rev1, target1, !useAncestry, depth, true, reporter, SVNCancellableEditor.newInstance(editor, this, getDebugLog())); } finally { if (editor != null) { editor.cleanup(); } repository2.closeSession(); } } private void doDiffURLURL(SVNURL url1, File path1, SVNRevision revision1, SVNURL url2, File path2, SVNRevision revision2, SVNRevision pegRevision, SVNDepth depth, boolean useAncestry, ISVNDiffStatusHandler handler) throws SVNException { File basePath = null; if (path1 != null) { basePath = path1; } if (path2 != null) { basePath = path2; } if (pegRevision.isValid()) { SVNRepositoryLocation[] locations = getLocations(url2, path2, null, pegRevision, revision1, revision2); url1 = locations[0].getURL(); url2 = locations[1].getURL(); getDiffGenerator().init(url1.toString(), url2.toString()); } else { url1 = url1 == null ? getURL(path1) : url1; url2 = url2 == null ? getURL(path2) : url2; } SVNRepository repository1 = createRepository(url1, null, null, true); SVNRepository repository2 = createRepository(url2, null, null, false); final long rev1 = getRevisionNumber(revision1, repository1, path1); long rev2 = -1; SVNNodeKind kind1 = null; SVNNodeKind kind2 = null; String target1 = null; try { rev2 = getRevisionNumber(revision2, repository2, path2); kind1 = repository1.checkPath("", rev1); kind2 = repository2.checkPath("", rev2); if (kind1 == SVNNodeKind.NONE) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.FS_NOT_FOUND, "''{0}'' was not found in the repository at revision {1}", new Object[] { url1, new Long(rev1) }); SVNErrorManager.error(err, SVNLogType.WC); } else if (kind2 == SVNNodeKind.NONE) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.FS_NOT_FOUND, "''{0}'' was not found in the repository at revision {1}", new Object[] { url2, new Long(rev2) }); SVNErrorManager.error(err, SVNLogType.WC); } if (kind1 == SVNNodeKind.FILE || kind2 == SVNNodeKind.FILE) { target1 = SVNPathUtil.tail(url1.getPath()); if (basePath != null) { basePath = basePath.getParentFile(); } url1 = SVNURL.parseURIEncoded(SVNPathUtil.removeTail(url1.toString())); repository1 = createRepository(url1, null, null, true); } } finally { repository2.closeSession(); } repository2 = createRepository(url1, null, null, false); File tmpFile = getDiffGenerator().createTempDirectory(); try { SVNDiffStatusEditor editor = new SVNDiffStatusEditor(basePath, target1, repository2, rev1, handler); ISVNReporterBaton reporter = new ISVNReporterBaton() { public void report(ISVNReporter reporter) throws SVNException { reporter.setPath("", null, rev1, SVNDepth.INFINITY, false); reporter.finishReport(); } }; repository1.diff(url2, rev2, rev1, target1, !useAncestry, depth, false, reporter, SVNCancellableEditor.newInstance(editor, this, getDebugLog())); } finally { if (tmpFile != null) { SVNFileUtil.deleteAll(tmpFile, true, null); } repository2.closeSession(); } } private int getAdminDepth(SVNDepth depth) { int admDepth = SVNWCAccess.INFINITE_DEPTH; if (depth == SVNDepth.IMMEDIATES) { admDepth = 1; } else if (depth == SVNDepth.EMPTY || depth == SVNDepth.FILES) { admDepth = 0; } return admDepth; } private Object[] getLocationFromPathAndRevision(File path, SVNURL url, SVNRevision pegRevision) throws SVNException { SVNWCAccess wcAccess = null; SVNRepository repos = null; SVNAdminArea adminArea = null; try { if (path != null && (pegRevision == SVNRevision.BASE || pegRevision == SVNRevision.WORKING || pegRevision == SVNRevision.COMMITTED || pegRevision == SVNRevision.UNDEFINED)) { int admLockLevel = getLevelsToLockFromDepth(SVNDepth.EMPTY); wcAccess = createWCAccess(); wcAccess.probeOpen(path, false, admLockLevel); } long[] rev = { SVNRepository.INVALID_REVISION }; repos = createRepository(url, path, adminArea, pegRevision, pegRevision, rev); return new Object[] { repos.getLocation(), SVNRevision.create(rev[0]) }; } finally { if (wcAccess != null) { wcAccess.close(); } if (repos != null) { repos.closeSession(); } } } private void getLogMergedMergeInfoImpl(File path, SVNURL url, SVNRevision pegRevision, SVNURL mergeSrcURL, File mergeSrcPath, SVNRevision srcPegRevision, boolean discoverChangedPaths, String[] revisionProperties, ISVNLogEntryHandler handler) throws SVNException { SVNURL reposRoot[] = new SVNURL[1]; Object[] location = getLocationFromPathAndRevision(mergeSrcPath, mergeSrcURL, srcPegRevision); SVNURL realMergeSrcURL = (SVNURL) location[0]; SVNRevision realSrcPegRevision = (SVNRevision) location[1]; Map targetMergeInfo = path != null ? getMergeInfo(path, pegRevision, reposRoot) : getMergeInfo(url, pegRevision, reposRoot); if (targetMergeInfo == null) { return; } Map srcHistory = getHistoryAsMergeInfo(realMergeSrcURL, null, realSrcPegRevision, SVNRepository.INVALID_REVISION, SVNRepository.INVALID_REVISION, null, null); Map mergeInfo = SVNMergeInfoUtil.intersectMergeInfo(targetMergeInfo, srcHistory, false); SVNMergeRangeList rangeList = new SVNMergeRangeList(new SVNMergeRange[0]); long youngestRev = SVNRepository.INVALID_REVISION; String logTarget = null; for (Iterator mergeInfoIter = mergeInfo.keySet().iterator(); mergeInfoIter.hasNext();) { String mergeSrc = (String) mergeInfoIter.next(); SVNMergeRangeList list = (SVNMergeRangeList) mergeInfo.get(mergeSrc); SVNMergeRange[] listRanges = list.getRanges(); SVNMergeRange range = listRanges[listRanges.length - 1]; if (!SVNRevision.isValidRevisionNumber(youngestRev) || range.getEndRevision() > youngestRev) { youngestRev = range.getEndRevision(); logTarget = mergeSrc; } rangeList = rangeList.merge(list); } if (rangeList.isEmpty()) { return; } getLogsForMergeInfoRangeList(reposRoot[0], new String[] { logTarget }, rangeList, discoverChangedPaths, revisionProperties, handler); } private void getLogEligibleMergeInfoImpl(File path, SVNURL url, SVNRevision pegRevision, SVNURL mergeSrcURL, File mergeSrcPath, SVNRevision srcPegRevision, boolean discoverChangedPaths, String[] revisionProperties, ISVNLogEntryHandler handler) throws SVNException { SVNURL reposRoot[] = new SVNURL[1]; Object[] location = getLocationFromPathAndRevision(mergeSrcPath, mergeSrcURL, srcPegRevision); SVNURL realMergeSrcURL = (SVNURL) location[0]; SVNRevision realSrcPegRevision = (SVNRevision) location[1]; Map mergeInfo = path != null ? getMergeInfo(path, pegRevision, reposRoot) : getMergeInfo(url, pegRevision, reposRoot); Map history = getHistoryAsMergeInfo(url, path, pegRevision, SVNRepository.INVALID_REVISION, SVNRepository.INVALID_REVISION, null, null); if (mergeInfo == null) { mergeInfo = history; } else { mergeInfo = SVNMergeInfoUtil.mergeMergeInfos(mergeInfo, history); } SVNRepository repos = null; Map sourceHistory = null; try { repos = createRepository(realMergeSrcURL, null, null, true); sourceHistory = getHistoryAsMergeInfo(realMergeSrcURL, null, realSrcPegRevision, SVNRepository.INVALID_REVISION, SVNRepository.INVALID_REVISION, repos, null); } finally { if (repos != null) { repos.closeSession(); } } Map availableMergeInfo = SVNMergeInfoUtil.removeMergeInfo(mergeInfo, sourceHistory, false); SVNMergeRangeList rangeList = new SVNMergeRangeList(new SVNMergeRange[0]); long youngestRev = SVNRepository.INVALID_REVISION; String logTarget = null; for (Iterator availableIter = availableMergeInfo.keySet().iterator(); availableIter.hasNext();) { String mergeSrc = (String) availableIter.next(); SVNMergeRangeList availableRangeList = (SVNMergeRangeList) availableMergeInfo.get(mergeSrc); SVNMergeRange[] ranges = availableRangeList.getRanges(); SVNMergeRange range = ranges[ranges.length - 1]; if (!SVNRevision.isValidRevisionNumber(youngestRev) || range.getEndRevision() > youngestRev) { youngestRev = range.getEndRevision(); logTarget = mergeSrc; } rangeList = rangeList.merge(availableRangeList); } if (rangeList.isEmpty()) { return; } getLogsForMergeInfoRangeList(reposRoot[0], new String[] { logTarget }, rangeList, discoverChangedPaths, revisionProperties, handler); } private void applyPatches(File absPatchPath, File absWCPath, boolean dryRun, int stripCount, SVNAdminArea wc) throws SVNException, IOException { final SVNPatchFileStream patchFile = SVNPatchFileStream.openReadOnly(absPatchPath); try { final List targets = new ArrayList(); SVNPatch patch; do { checkCancelled(); patch = SVNPatch.parseNextPatch(patchFile); if (patch != null) { final SVNPatchTarget target = SVNPatchTarget.applyPatch(patch, absWCPath, stripCount, wc); targets.add(target); } } while (patch != null); for (Iterator i = targets.iterator(); i.hasNext();) { checkCancelled(); final SVNPatchTarget target = (SVNPatchTarget) i.next(); if (!target.isSkipped()) { target.installPatchedTarget(absWCPath, dryRun, wc); } target.sendPatchNotification(wc); target.getPatch().close(); } } catch (IOException e) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e.getMessage(), null, 0, e); SVNErrorManager.error(err, Level.FINE, SVNLogType.WC); } finally { if (patchFile != null) { patchFile.close(); } } } public void doPatch(File absPatchPath, File localAbsPath, boolean dryRun, int stripCount) throws SVNException { if (stripCount < 0) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.INCORRECT_PARAMS, "strip count must be positive"); SVNErrorManager.error(err, SVNLogType.CLIENT); } final SVNWCAccess wcAccess = createWCAccess(); try { wcAccess.setEventHandler(this); final SVNAdminArea wc = wcAccess.open(localAbsPath, true, SVNWCAccess.INFINITE_DEPTH); applyPatches(absPatchPath, localAbsPath, dryRun, stripCount, wc); } catch (IOException e) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e.getMessage()); SVNErrorManager.error(err, SVNLogType.CLIENT); } finally { wcAccess.close(); } } }