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();
}
}
}