Source Code Cross Referenced for SVNDiffClient.java in  » Source-Control » tmatesoft-SVN » org » tmatesoft » svn » core » wc » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Source Control » tmatesoft SVN » org.tmatesoft.svn.core.wc 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * ====================================================================
0003:         * Copyright (c) 2004-2008 TMate Software Ltd.  All rights reserved.
0004:         *
0005:         * This software is licensed as described in the file COPYING, which
0006:         * you should have received as part of this distribution.  The terms
0007:         * are also available at http://svnkit.com/license.html
0008:         * If newer versions of this license are posted there, you may use a
0009:         * newer version instead, at your option.
0010:         * ====================================================================
0011:         */
0012:        package org.tmatesoft.svn.core.wc;
0013:
0014:        import java.io.File;
0015:        import java.io.OutputStream;
0016:        import java.util.HashMap;
0017:        import java.util.Iterator;
0018:        import java.util.Map;
0019:
0020:        import org.tmatesoft.svn.core.SVNErrorCode;
0021:        import org.tmatesoft.svn.core.SVNErrorMessage;
0022:        import org.tmatesoft.svn.core.SVNException;
0023:        import org.tmatesoft.svn.core.SVNNodeKind;
0024:        import org.tmatesoft.svn.core.SVNProperty;
0025:        import org.tmatesoft.svn.core.SVNURL;
0026:        import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
0027:        import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
0028:        import org.tmatesoft.svn.core.internal.wc.AbstractDiffCallback;
0029:        import org.tmatesoft.svn.core.internal.wc.SVNCancellableEditor;
0030:        import org.tmatesoft.svn.core.internal.wc.SVNCancellableOutputStream;
0031:        import org.tmatesoft.svn.core.internal.wc.SVNDiffCallback;
0032:        import org.tmatesoft.svn.core.internal.wc.SVNDiffEditor;
0033:        import org.tmatesoft.svn.core.internal.wc.SVNDiffStatusEditor;
0034:        import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
0035:        import org.tmatesoft.svn.core.internal.wc.SVNEventFactory;
0036:        import org.tmatesoft.svn.core.internal.wc.SVNFileUtil;
0037:        import org.tmatesoft.svn.core.internal.wc.SVNMergeCallback;
0038:        import org.tmatesoft.svn.core.internal.wc.SVNRemoteDiffEditor;
0039:        import org.tmatesoft.svn.core.internal.wc.admin.SVNAdminAreaInfo;
0040:        import org.tmatesoft.svn.core.internal.wc.admin.SVNEntry;
0041:        import org.tmatesoft.svn.core.internal.wc.admin.SVNReporter;
0042:        import org.tmatesoft.svn.core.internal.wc.admin.SVNWCAccess;
0043:        import org.tmatesoft.svn.core.io.ISVNReporter;
0044:        import org.tmatesoft.svn.core.io.ISVNReporterBaton;
0045:        import org.tmatesoft.svn.core.io.SVNRepository;
0046:
0047:        /**
0048:         * The <b>SVNDiffClient</b> class provides methods allowing to get differences
0049:         * between versioned items ('diff' operation) as well as ones intended for 
0050:         * merging file contents.
0051:         * 
0052:         * <p>
0053:         * Here's a list of the <b>SVNDiffClient</b>'s methods 
0054:         * matched against corresponing commands of the SVN command line 
0055:         * client:
0056:         * 
0057:         * <table cellpadding="3" cellspacing="1" border="0" width="40%" bgcolor="#999933">
0058:         * <tr bgcolor="#ADB8D9" align="left">
0059:         * <td><b>SVNKit</b></td>
0060:         * <td><b>Subversion</b></td>
0061:         * </tr>   
0062:         * <tr bgcolor="#EAEAEA" align="left">
0063:         * <td>doDiff()</td><td>'svn diff'</td>
0064:         * </tr>
0065:         * <tr bgcolor="#EAEAEA" align="left">
0066:         * <td>doDiffStatus()</td><td>'svn diff --summarize'</td>
0067:         * </tr>
0068:         * <tr bgcolor="#EAEAEA" align="left">
0069:         * <td>doMerge()</td><td>'svn merge'</td>
0070:         * </tr>
0071:         * </table>
0072:         * 
0073:         * @version 1.1.1
0074:         * @author  TMate Software Ltd.
0075:         */
0076:        public class SVNDiffClient extends SVNBasicClient {
0077:
0078:            private ISVNDiffGenerator myDiffGenerator;
0079:            private SVNDiffOptions myDiffOptions;
0080:
0081:            /**
0082:             * Constructs and initializes an <b>SVNDiffClient</b> object
0083:             * with the specified run-time configuration and authentication 
0084:             * drivers.
0085:             * 
0086:             * <p>
0087:             * If <code>options</code> is <span class="javakeyword">null</span>,
0088:             * then this <b>SVNDiffClient</b> will be using a default run-time
0089:             * configuration driver  which takes client-side settings from the 
0090:             * default SVN's run-time configuration area but is not able to
0091:             * change those settings (read more on {@link ISVNOptions} and {@link SVNWCUtil}).  
0092:             * 
0093:             * <p>
0094:             * If <code>authManager</code> is <span class="javakeyword">null</span>,
0095:             * then this <b>SVNDiffClient</b> will be using a default authentication
0096:             * and network layers driver (see {@link SVNWCUtil#createDefaultAuthenticationManager()})
0097:             * which uses server-side settings and auth storage from the 
0098:             * default SVN's run-time configuration area (or system properties
0099:             * if that area is not found).
0100:             * 
0101:             * @param authManager an authentication and network layers driver
0102:             * @param options     a run-time configuration options driver     
0103:             */
0104:            public SVNDiffClient(ISVNAuthenticationManager authManager,
0105:                    ISVNOptions options) {
0106:                super (authManager, options);
0107:            }
0108:
0109:            public SVNDiffClient(ISVNRepositoryPool repositoryPool,
0110:                    ISVNOptions options) {
0111:                super (repositoryPool, options);
0112:            }
0113:
0114:            /**
0115:             * Sets the specified diff driver for this object to use for
0116:             * generating and writing file differences to an otput stream.
0117:             * 
0118:             * <p>
0119:             * If no specific diff driver was set in this way, a default one
0120:             * will be used (see {@link DefaultSVNDiffGenerator}). 
0121:             * 
0122:             * @param diffGenerator a diff driver
0123:             * @see   #getDiffGenerator()
0124:             */
0125:            public void setDiffGenerator(ISVNDiffGenerator diffGenerator) {
0126:                myDiffGenerator = diffGenerator;
0127:            }
0128:
0129:            /**
0130:             * Returns the diff driver being in use.
0131:             *  
0132:             * <p>
0133:             * If no specific diff driver was previously provided, a default one
0134:             * will be returned (see {@link DefaultSVNDiffGenerator}). 
0135:             * 
0136:             * @return the diff driver being in use
0137:             * @see    #setDiffGenerator(ISVNDiffGenerator)
0138:             */
0139:            public ISVNDiffGenerator getDiffGenerator() {
0140:                if (myDiffGenerator == null) {
0141:                    myDiffGenerator = new DefaultSVNDiffGenerator();
0142:                }
0143:                return myDiffGenerator;
0144:            }
0145:
0146:            /**
0147:             * Sets diff options for this client to use in merge operations.
0148:             * 
0149:             * @param diffOptions diff options object
0150:             */
0151:            public void setMergeOptions(SVNDiffOptions diffOptions) {
0152:                myDiffOptions = diffOptions;
0153:            }
0154:
0155:            /**
0156:             * Gets the diff options that are used in merge operations 
0157:             * by this client. Creates a new one if none was used before.
0158:             * 
0159:             * @return diff options
0160:             */
0161:            public SVNDiffOptions getMergeOptions() {
0162:                if (myDiffOptions == null) {
0163:                    myDiffOptions = new SVNDiffOptions();
0164:                }
0165:                return myDiffOptions;
0166:            }
0167:
0168:            /**
0169:             * Generates the differences for the specified URL taken from the two 
0170:             * specified revisions and writes the result to the provided output
0171:             * stream.
0172:             * 
0173:             * <p>
0174:             * Corresponds to the SVN command line client's 
0175:             * <code>'svn diff -r N:M URL'</code> command.
0176:             * 
0177:             * @param  url            a repository location
0178:             * @param  pegRevision    a revision in which <code>url</code> is first looked up
0179:             * @param  rN             an old revision                          
0180:             * @param  rM             a new revision
0181:             * @param  recursive      <span class="javakeyword">true</span> to descend 
0182:             *                        recursively
0183:             * @param  useAncestry    if <span class="javakeyword">true</span> then
0184:             *                        the paths ancestry will be noticed while calculating differences,
0185:             *                        otherwise not
0186:             * @param  result         the target {@link java.io.OutputStream} where
0187:             *                        the differences will be written to
0188:             * @throws SVNException   if one of the following is true:
0189:             *                        <ul>
0190:             *                        <li>at least one of <code>rN</code>, <code>rM</code> and
0191:             *                        <code>pegRevision</code> is invalid
0192:             *                        <li>at least one of <code>rN</code> and <code>rM</code> is
0193:             *                        a local revision (see {@link SVNRevision#isLocal()})
0194:             *                        <li><code>url</code> was not found in <code>rN</code>
0195:             *                        <li><code>url</code> was not found in <code>rM</code>
0196:             *                        </ul>
0197:             */
0198:            public void doDiff(SVNURL url, SVNRevision pegRevision,
0199:                    SVNRevision rN, SVNRevision rM, boolean recursive,
0200:                    boolean useAncestry, OutputStream result)
0201:                    throws SVNException {
0202:                if (!rN.isValid() || !rM.isValid()) {
0203:                    SVNErrorMessage err = SVNErrorMessage.create(
0204:                            SVNErrorCode.CLIENT_BAD_REVISION,
0205:                            "Both rN and rM revisions should be specified");
0206:                    SVNErrorManager.error(err);
0207:                }
0208:                if (rN.isLocal() || rM.isLocal()) {
0209:                    SVNErrorMessage err = SVNErrorMessage.create(
0210:                            SVNErrorCode.CLIENT_BAD_REVISION,
0211:                            "Both rN and rM revisions must be non-local for "
0212:                                    + "a pegged diff of an URL");
0213:                    SVNErrorManager.error(err);
0214:                }
0215:                getDiffGenerator().init(url.toString(), url.toString());
0216:                doDiffURLURL(url, null, rN, url, null, rM, pegRevision,
0217:                        recursive, useAncestry, result);
0218:            }
0219:
0220:            /**
0221:             * Generates the differences for the specified path taken from the two 
0222:             * specified revisions and writes the result to the provided output
0223:             * stream.
0224:             * 
0225:             * <p>
0226:             * If <code>rM</code> is a local revision (see {@link SVNRevision#isLocal()}),
0227:             * then the Working Copy <code>path</code> is compared with the corresponding 
0228:             * repository file at revision <code>rN</code> (that is similar to the SVN command 
0229:             * line client's <code>'svn diff -r N path'</code> command). 
0230:             * 
0231:             * <p>
0232:             * Otherwise if both <code>rN</code> and <code>rM</code> are non-local, then 
0233:             * the repository location of <code>path</code> is compared for these 
0234:             * revisions (<code>'svn diff -r N:M URL'</code>).
0235:             * 
0236:             * @param  path           a Working Copy file path
0237:             * @param  pegRevision    a revision in which the repository location of <code>path</code> 
0238:             *                        is first looked up
0239:             * @param  rN             an old revision                          
0240:             * @param  rM             a new revision (or a local one)
0241:             * @param  recursive      <span class="javakeyword">true</span> to descend 
0242:             *                        recursively
0243:             * @param  useAncestry    if <span class="javakeyword">true</span> then
0244:             *                        the paths ancestry will be noticed while calculating differences,
0245:             *                        otherwise not
0246:             * @param  result         the target {@link java.io.OutputStream} where
0247:             *                        the differences will be written to
0248:             * @throws SVNException   if one of the following is true:
0249:             *                        <ul>
0250:             *                        <li>at least one of <code>rN</code>, <code>rM</code> and
0251:             *                        <code>pegRevision</code> is invalid
0252:             *                        <li>both <code>rN</code> and <code>rM</code> are 
0253:             *                        local revisions
0254:             *                        <li><code>path</code> was not found in <code>rN</code>
0255:             *                        <li><code>path</code> was not found in <code>rM</code>
0256:             *                        </ul>
0257:             */
0258:            public void doDiff(File path, SVNRevision pegRevision,
0259:                    SVNRevision rN, SVNRevision rM, boolean recursive,
0260:                    boolean useAncestry, OutputStream result)
0261:                    throws SVNException {
0262:                if (!rN.isValid() || !rM.isValid()) {
0263:                    SVNErrorMessage err = SVNErrorMessage.create(
0264:                            SVNErrorCode.CLIENT_BAD_REVISION,
0265:                            "Both rN and rM revisions should be specified");
0266:                    SVNErrorManager.error(err);
0267:                }
0268:                if (rN.isLocal() && rM.isLocal()) {
0269:                    SVNErrorMessage err = SVNErrorMessage.create(
0270:                            SVNErrorCode.CLIENT_BAD_REVISION,
0271:                            "At least one revision must be non-local for "
0272:                                    + "a pegged diff");
0273:                    SVNErrorManager.error(err);
0274:                }
0275:                path = new File(SVNPathUtil.validateFilePath(path
0276:                        .getAbsolutePath())).getAbsoluteFile();
0277:                getDiffGenerator().init(path.getAbsolutePath(),
0278:                        path.getAbsolutePath());
0279:                if (!(rM == SVNRevision.BASE || rM == SVNRevision.WORKING || rM == SVNRevision.COMMITTED)) {
0280:                    if ((rN == SVNRevision.BASE || rN == SVNRevision.WORKING || rN == SVNRevision.COMMITTED)) {
0281:                        doDiffURLWC(path, rM, pegRevision, path, rN, true,
0282:                                recursive, useAncestry, result);
0283:                    } else {
0284:                        doDiffURLURL(null, path, rN, null, path, rM,
0285:                                pegRevision, recursive, useAncestry, result);
0286:                    }
0287:                } else {
0288:                    // head, prev,date,number will go here.
0289:                    doDiffURLWC(path, rN, pegRevision, path, rM, false,
0290:                            recursive, useAncestry, result);
0291:                }
0292:            }
0293:
0294:            /**
0295:             * Generates the differences for the specified URLs taken from the two 
0296:             * specified revisions and writes the result to the provided output
0297:             * stream.
0298:             * 
0299:             * <p>
0300:             * Corresponds to the SVN command line client's 
0301:             * <code>'svn diff -r N:M URL1 URL2'</code> command.
0302:             * 
0303:             * @param  url1           the first URL to be compared
0304:             * @param  rN             a revision of <code>url1</code>
0305:             * @param  url2           the second URL to be compared
0306:             * @param  rM             a revision of <code>url2</code>
0307:             * @param  recursive      <span class="javakeyword">true</span> to descend 
0308:             *                        recursively
0309:             * @param  useAncestry    if <span class="javakeyword">true</span> then
0310:             *                        the paths ancestry will be noticed while calculating differences,
0311:             *                        otherwise not
0312:             * @param  result         the target {@link java.io.OutputStream} where
0313:             *                        the differences will be written to
0314:             * @throws SVNException   if one of the following is true:
0315:             *                        <ul>
0316:             *                        <li>at least one of <code>rN</code> and <code>rM</code> is
0317:             *                        invalid
0318:             *                        <li><code>url1</code> was not found in <code>rN</code>
0319:             *                        <li><code>url2</code> was not found in <code>rM</code>
0320:             *                        </ul>
0321:             */
0322:            public void doDiff(SVNURL url1, SVNRevision rN, SVNURL url2,
0323:                    SVNRevision rM, boolean recursive, boolean useAncestry,
0324:                    OutputStream result) throws SVNException {
0325:                if (!rN.isValid() || !rM.isValid()) {
0326:                    SVNErrorMessage err = SVNErrorMessage.create(
0327:                            SVNErrorCode.CLIENT_BAD_REVISION,
0328:                            "Both rN and rM revisions should be specified");
0329:                    SVNErrorManager.error(err);
0330:                }
0331:                getDiffGenerator().init(url1.toString(), url2.toString());
0332:                doDiffURLURL(url1, null, rN, url2, null, rM,
0333:                        SVNRevision.UNDEFINED, recursive, useAncestry, result);
0334:            }
0335:
0336:            /**
0337:             * Generates the differences comparing the specified URL in a certain 
0338:             * revision against either the specified Working Copy path or its repository 
0339:             * location URL in the specified revision, and writes the result to the provided output
0340:             * stream.
0341:             * 
0342:             * <p>
0343:             * If <code>rN</code> is not a local revision (see {@link SVNRevision#isLocal()}),
0344:             * then its repository location URL as it is in the revision represented by 
0345:             * <code>rN</code> is taken for comparison with <code>url2</code>.
0346:             * 
0347:             * <p>
0348:             * Corresponds to the SVN command line client's 
0349:             * <code>'svn diff -r N:M PATH URL'</code> command.
0350:             * 
0351:             * @param  path1          a WC path  
0352:             * @param  rN             a revision of <code>path1</code>
0353:             * @param  url2           a repository location URL that is to be compared 
0354:             *                        against <code>path1</code> (or its repository location)
0355:             * @param  rM             a revision of <code>url2</code> 
0356:             * @param  recursive      <span class="javakeyword">true</span> to descend 
0357:             *                        recursively
0358:             * @param  useAncestry    if <span class="javakeyword">true</span> then
0359:             *                        the paths ancestry will be noticed while calculating differences,
0360:             *                        otherwise not
0361:             * @param  result         the target {@link java.io.OutputStream} where
0362:             *                        the differences will be written to
0363:             * @throws SVNException   if one of the following is true:
0364:             *                        <ul>
0365:             *                        <li>at least one of <code>rN</code> and <code>rM</code> is
0366:             *                        invalid
0367:             *                        <li><code>path1</code> is not under version control
0368:             *                        <li><code>path1</code> has no URL
0369:             *                        <li><code>url2</code> was not found in <code>rM</code>
0370:             *                        <li>the repository location of <code>path1</code> was 
0371:             *                        not found in <code>rN</code>
0372:             *                        </ul>
0373:             */
0374:            public void doDiff(File path1, SVNRevision rN, SVNURL url2,
0375:                    SVNRevision rM, boolean recursive, boolean useAncestry,
0376:                    OutputStream result) throws SVNException {
0377:                if (!rN.isValid() || !rM.isValid()) {
0378:                    SVNErrorMessage err = SVNErrorMessage.create(
0379:                            SVNErrorCode.CLIENT_BAD_REVISION,
0380:                            "Both rN and rM revisions should be specified");
0381:                    SVNErrorManager.error(err);
0382:                }
0383:                getDiffGenerator().init(path1.getAbsolutePath(),
0384:                        url2.toString());
0385:                if (rN == SVNRevision.BASE || rN == SVNRevision.WORKING) {
0386:                    doDiffURLWC(url2, rM, SVNRevision.UNDEFINED, path1, rN,
0387:                            true, recursive, useAncestry, result);
0388:                } else {
0389:                    doDiffURLURL(null, path1, rN, url2, null, rM,
0390:                            SVNRevision.UNDEFINED, recursive, useAncestry,
0391:                            result);
0392:                }
0393:            }
0394:
0395:            /**
0396:             * Generates the differences comparing either the specified Working Copy path or 
0397:             * its repository location URL in the specified revision against the specified URL 
0398:             * in a certain revision, and writes the result to the provided output stream.
0399:             * 
0400:             * <p>
0401:             * If <code>rM</code> is not a local revision (see {@link SVNRevision#isLocal()}),
0402:             * then its repository location URL as it is in the revision represented by 
0403:             * <code>rM</code> is taken for comparison with <code>url1</code>.
0404:             * 
0405:             * <p>
0406:             * Corresponds to the SVN command line client's 
0407:             * <code>'svn diff -r N:M URL PATH'</code> command.
0408:             * 
0409:             * @param  url1           a repository location URL 
0410:             * @param  rN             a revision of <code>url1</code>
0411:             * @param  path2          a WC path that is to be compared 
0412:             *                        against <code>url1</code>
0413:             * @param  rM             a revision of <code>path2</code>
0414:             * @param  recursive      <span class="javakeyword">true</span> to descend 
0415:             *                        recursively
0416:             * @param  useAncestry    if <span class="javakeyword">true</span> then
0417:             *                        the paths ancestry will be noticed while calculating differences,
0418:             *                        otherwise not
0419:             * @param  result         the target {@link java.io.OutputStream} where
0420:             *                        the differences will be written to
0421:             * @throws SVNException   if one of the following is true:
0422:             *                        <ul>
0423:             *                        <li>at least one of <code>rN</code> and <code>rM</code> is
0424:             *                        invalid
0425:             *                        <li><code>path2</code> is not under version control
0426:             *                        <li><code>path2</code> has no URL
0427:             *                        <li><code>url1</code> was not found in <code>rN</code>
0428:             *                        <li>the repository location of <code>path2</code> was 
0429:             *                        not found in <code>rM</code>
0430:             *                        </ul>
0431:             */
0432:            public void doDiff(SVNURL url1, SVNRevision rN, File path2,
0433:                    SVNRevision rM, boolean recursive, boolean useAncestry,
0434:                    OutputStream result) throws SVNException {
0435:                if (!rN.isValid() || !rM.isValid()) {
0436:                    SVNErrorMessage err = SVNErrorMessage.create(
0437:                            SVNErrorCode.CLIENT_BAD_REVISION,
0438:                            "Both rN and rM revisions should be specified");
0439:                    SVNErrorManager.error(err);
0440:                }
0441:                getDiffGenerator().init(url1.toString(),
0442:                        path2.getAbsolutePath());
0443:                if (rM == SVNRevision.BASE || rM == SVNRevision.WORKING) {
0444:                    doDiffURLWC(url1, rN, SVNRevision.UNDEFINED, path2, rM,
0445:                            false, recursive, useAncestry, result);
0446:                } else {
0447:                    doDiffURLURL(url1, null, rN, null, path2, rM,
0448:                            SVNRevision.UNDEFINED, recursive, useAncestry,
0449:                            result);
0450:                }
0451:            }
0452:
0453:            /**
0454:             * Generates the differences comparing either the specified Working Copy paths or 
0455:             * their repository location URLs (any combinations are possible) in the specified 
0456:             * revisions and writes the result to the provided output stream.
0457:             * 
0458:             * <p>
0459:             * If both <code>rN</code> and <code>rM</code> are local revisions (see {@link SVNRevision#isLocal()}),
0460:             * then a Working Copy <code>path2</code> is compared against a Working Copy <code>path1</code>.
0461:             * 
0462:             * <p>
0463:             * If <code>rN</code> is a local revision but <code>rM</code> is not, then
0464:             * the repository location URL of <code>path2</code> as it is in the revision 
0465:             * represented by <code>rM</code> is compared against the Working Copy <code>path1</code>.
0466:             *
0467:             * <p>
0468:             * If <code>rM</code> is a local revision but <code>rN</code> is not, then
0469:             * the Working Copy <code>path2</code> is compared against the repository location 
0470:             * URL of <code>path1</code> as it is in the revision represented by <code>rN</code>.
0471:             * 
0472:             * <p>
0473:             * If both <code>rN</code> and <code>rM</code> are non-local revisions, then the
0474:             * repository location URL of <code>path2</code> in revision <code>rM</code> is 
0475:             * compared against the repository location URL of <code>path1</code> in revision 
0476:             * <code>rN</code>.
0477:             * 
0478:             * @param  path1          a WC path
0479:             * @param  rN             a revision of <code>path1</code>
0480:             * @param  path2          a WC path that is to be compared 
0481:             *                        against <code>path1</code>
0482:             * @param  rM             a revision of <code>path2</code>
0483:             * @param  recursive      <span class="javakeyword">true</span> to descend 
0484:             *                        recursively
0485:             * @param  useAncestry    if <span class="javakeyword">true</span> then
0486:             *                        the paths ancestry will be noticed while calculating differences,
0487:             *                        otherwise not
0488:             * @param  result         the target {@link java.io.OutputStream} where
0489:             *                        the differences will be written to
0490:             * @throws SVNException   if one of the following is true:
0491:             *                        <ul>
0492:             *                        <li>at least one of <code>rN</code> and <code>rM</code> is
0493:             *                        invalid
0494:             *                        <li><code>path1</code> is not under version control
0495:             *                        <li><code>path1</code> has no URL
0496:             *                        <li><code>path2</code> is not under version control
0497:             *                        <li><code>path2</code> has no URL
0498:             *                        <li>the repository location of <code>path1</code> was 
0499:             *                        not found in <code>rN</code>
0500:             *                        <li>the repository location of <code>path2</code> was 
0501:             *                        not found in <code>rM</code>
0502:             *                        <li>both <code>rN</code> and <code>rM</code> are local,
0503:             *                        but either <code>path1</code> does not equal <code>path2</code>,
0504:             *                        or <code>rN</code> is not {@link SVNRevision#BASE}, or
0505:             *                        <code>rM</code> is not {@link SVNRevision#WORKING} 
0506:             *                        </ul>
0507:             */
0508:            public void doDiff(File path1, SVNRevision rN, File path2,
0509:                    SVNRevision rM, boolean recursive, boolean useAncestry,
0510:                    OutputStream result) throws SVNException {
0511:                if (!rN.isValid() || !rM.isValid()) {
0512:                    SVNErrorMessage err = SVNErrorMessage.create(
0513:                            SVNErrorCode.CLIENT_BAD_REVISION,
0514:                            "Both rN and rM revisions should be specified");
0515:                    SVNErrorManager.error(err);
0516:                }
0517:
0518:                boolean isPath1Local = rN == SVNRevision.WORKING
0519:                        || rN == SVNRevision.BASE;
0520:                boolean isPath2Local = rM == SVNRevision.WORKING
0521:                        || rM == SVNRevision.BASE;
0522:                getDiffGenerator().init(path1.getAbsolutePath(),
0523:                        path2.getAbsolutePath());
0524:                if (isPath1Local && isPath2Local) {
0525:                    doDiffWCWC(path1, rN, path2, rM, recursive, useAncestry,
0526:                            result);
0527:                } else if (isPath1Local) {
0528:                    doDiffURLWC(path2, rM, SVNRevision.UNDEFINED, path1, rN,
0529:                            true, recursive, useAncestry, result);
0530:                } else if (isPath2Local) {
0531:                    doDiffURLWC(path1, rN, SVNRevision.UNDEFINED, path2, rM,
0532:                            false, recursive, useAncestry, result);
0533:                } else {
0534:                    doDiffURLURL(null, path1, rN, null, path2, rM,
0535:                            SVNRevision.UNDEFINED, recursive, useAncestry,
0536:                            result);
0537:                }
0538:            }
0539:
0540:            /**
0541:             * Diffs one path against another one providing short status-like change information to the provided
0542:             * handler. This method functionality is equivalent to the 'svn diff --summarize' command.
0543:             * 
0544:             * @param  path1             the path of a left-hand item to diff
0545:             * @param  rN                a revision of <code>path1</code>
0546:             * @param  path2             the path of a right-hand item to diff
0547:             * @param  rM                a revision of <code>path2</code>
0548:             * @param  recursive         controls whether operation must recurse or not 
0549:             * @param  useAncestry       if <span class="javakeyword">true</span> then
0550:             *                           the paths ancestry will be noticed while calculating differences,
0551:             *                           otherwise not
0552:             * @param  handler           a diff status handler
0553:             * @throws SVNException
0554:             * @since                    1.1, new in Subversion 1.4
0555:             */
0556:            public void doDiffStatus(File path1, SVNRevision rN, File path2,
0557:                    SVNRevision rM, boolean recursive, boolean useAncestry,
0558:                    ISVNDiffStatusHandler handler) throws SVNException {
0559:                if (handler == null) {
0560:                    return;
0561:                }
0562:                if (!rN.isValid() || !rM.isValid()) {
0563:                    SVNErrorMessage err = SVNErrorMessage.create(
0564:                            SVNErrorCode.CLIENT_BAD_REVISION,
0565:                            "Both rN and rM revisions should be specified");
0566:                    SVNErrorManager.error(err);
0567:                }
0568:
0569:                boolean isPath1Local = rN == SVNRevision.WORKING
0570:                        || rN == SVNRevision.BASE;
0571:                boolean isPath2Local = rM == SVNRevision.WORKING
0572:                        || rM == SVNRevision.BASE;
0573:                if (isPath1Local || isPath2Local) {
0574:                    SVNErrorMessage err = SVNErrorMessage
0575:                            .create(SVNErrorCode.UNSUPPORTED_FEATURE,
0576:                                    "Summarizing diff can only compare repository to repository");
0577:                    SVNErrorManager.error(err);
0578:                }
0579:                doDiffURLURL(null, path1, rN, null, path2, rM,
0580:                        SVNRevision.UNDEFINED, recursive, useAncestry, handler);
0581:            }
0582:
0583:            /**
0584:             * Diffs a path against a url providing short status-like change information to the provided
0585:             * handler. This method functionality is equivalent to the 'svn diff --summarize' command.
0586:             * 
0587:             * @param  path1             the path of a left-hand item to diff
0588:             * @param  rN                a revision of <code>path1</code>
0589:             * @param  url2              the url of a right-hand item to diff
0590:             * @param  rM                a revision of <code>url2</code>
0591:             * @param  recursive         controls whether operation must recurse or not 
0592:             * @param  useAncestry       if <span class="javakeyword">true</span> then
0593:             *                           the paths ancestry will be noticed while calculating differences,
0594:             *                           otherwise not
0595:             * @param  handler           a diff status handler
0596:             * @throws SVNException
0597:             * @since                    1.1, new in Subversion 1.4
0598:             */
0599:            public void doDiffStatus(File path1, SVNRevision rN, SVNURL url2,
0600:                    SVNRevision rM, boolean recursive, boolean useAncestry,
0601:                    ISVNDiffStatusHandler handler) throws SVNException {
0602:                if (handler == null) {
0603:                    return;
0604:                }
0605:                if (!rN.isValid() || !rM.isValid()) {
0606:                    SVNErrorMessage err = SVNErrorMessage.create(
0607:                            SVNErrorCode.CLIENT_BAD_REVISION,
0608:                            "Both rN and rM revisions should be specified");
0609:                    SVNErrorManager.error(err);
0610:                }
0611:                if (rN == SVNRevision.BASE || rN == SVNRevision.WORKING) {
0612:                    SVNErrorMessage err = SVNErrorMessage
0613:                            .create(SVNErrorCode.UNSUPPORTED_FEATURE,
0614:                                    "Summarizing diff can only compare repository to repository");
0615:                    SVNErrorManager.error(err);
0616:                } else {
0617:                    doDiffURLURL(null, path1, rN, url2, null, rM,
0618:                            SVNRevision.UNDEFINED, recursive, useAncestry,
0619:                            handler);
0620:                }
0621:            }
0622:
0623:            /**
0624:             * Diffs a url against a path providing short status-like change information to the provided
0625:             * handler. This method functionality is equivalent to the 'svn diff --summarize' command.
0626:             * 
0627:             * @param  url1              the url of a left-hand item to diff
0628:             * @param  rN                a revision of <code>url1</code>
0629:             * @param  path2             the path of a right-hand item to diff
0630:             * @param  rM                a revision of <code>path2</code>
0631:             * @param  recursive         controls whether operation must recurse or not 
0632:             * @param  useAncestry       if <span class="javakeyword">true</span> then
0633:             *                           the paths ancestry will be noticed while calculating differences,
0634:             *                           otherwise not
0635:             * @param  handler           a diff status handler
0636:             * @throws SVNException
0637:             * @since                    1.1, new in Subversion 1.4
0638:             */
0639:            public void doDiffStatus(SVNURL url1, SVNRevision rN, File path2,
0640:                    SVNRevision rM, boolean recursive, boolean useAncestry,
0641:                    ISVNDiffStatusHandler handler) throws SVNException {
0642:                if (handler == null) {
0643:                    return;
0644:                }
0645:                if (!rN.isValid() || !rM.isValid()) {
0646:                    SVNErrorMessage err = SVNErrorMessage.create(
0647:                            SVNErrorCode.CLIENT_BAD_REVISION,
0648:                            "Both rN and rM revisions should be specified");
0649:                    SVNErrorManager.error(err);
0650:                }
0651:                if (rM == SVNRevision.BASE || rM == SVNRevision.WORKING) {
0652:                    SVNErrorMessage err = SVNErrorMessage
0653:                            .create(SVNErrorCode.UNSUPPORTED_FEATURE,
0654:                                    "Summarizing diff can only compare repository to repository");
0655:                    SVNErrorManager.error(err);
0656:                } else {
0657:                    doDiffURLURL(url1, null, rN, null, path2, rM,
0658:                            SVNRevision.UNDEFINED, recursive, useAncestry,
0659:                            handler);
0660:                }
0661:            }
0662:
0663:            /**
0664:             * Diffs one url against another one providing short status-like change information to the provided
0665:             * handler. This method functionality is equivalent to the 'svn diff --summarize' command.
0666:             * 
0667:             * @param  url1              the url of a left-hand item to diff
0668:             * @param  rN                a revision of <code>url1</code>
0669:             * @param  url2              the url of a right-hand item to diff
0670:             * @param  rM                a revision of <code>url2</code>
0671:             * @param  recursive         controls whether operation must recurse or not 
0672:             * @param  useAncestry       if <span class="javakeyword">true</span> then
0673:             *                           the paths ancestry will be noticed while calculating differences,
0674:             *                           otherwise not
0675:             * @param  handler           a diff status handler
0676:             * @throws SVNException
0677:             * @since                    1.1, new in Subversion 1.4
0678:             */
0679:            public void doDiffStatus(SVNURL url1, SVNRevision rN, SVNURL url2,
0680:                    SVNRevision rM, boolean recursive, boolean useAncestry,
0681:                    ISVNDiffStatusHandler handler) throws SVNException {
0682:                if (handler == null) {
0683:                    return;
0684:                }
0685:                if (!rN.isValid() || !rM.isValid()) {
0686:                    SVNErrorMessage err = SVNErrorMessage.create(
0687:                            SVNErrorCode.CLIENT_BAD_REVISION,
0688:                            "Both rN and rM revisions should be specified");
0689:                    SVNErrorManager.error(err);
0690:                }
0691:                doDiffURLURL(url1, null, rN, url2, null, rM,
0692:                        SVNRevision.UNDEFINED, recursive, useAncestry, handler);
0693:            }
0694:
0695:            private void doDiffURLWC(SVNURL url1, SVNRevision revision1,
0696:                    SVNRevision pegRevision, File path2, SVNRevision revision2,
0697:                    boolean reverse, boolean recursive, boolean useAncestry,
0698:                    OutputStream result) throws SVNException {
0699:                SVNWCAccess wcAccess = createWCAccess();
0700:                try {
0701:                    SVNAdminAreaInfo info = wcAccess.openAnchor(path2, false,
0702:                            recursive ? SVNWCAccess.INFINITE_DEPTH : 0);
0703:                    File anchorPath = info.getAnchor().getRoot();
0704:                    String target = "".equals(info.getTargetName()) ? null
0705:                            : info.getTargetName();
0706:
0707:                    SVNEntry anchorEntry = info.getAnchor().getEntry("", false);
0708:                    if (anchorEntry == null) {
0709:                        SVNErrorMessage err = SVNErrorMessage.create(
0710:                                SVNErrorCode.ENTRY_NOT_FOUND,
0711:                                "''{0}'' is not under version control",
0712:                                anchorPath);
0713:                        SVNErrorManager.error(err);
0714:                    } else if (anchorEntry.getURL() == null) {
0715:                        SVNErrorMessage err = SVNErrorMessage.create(
0716:                                SVNErrorCode.ENTRY_MISSING_URL,
0717:                                "''{0}'' has no URL", anchorPath);
0718:                        SVNErrorManager.error(err);
0719:                    }
0720:                    SVNURL anchorURL = anchorEntry.getSVNURL();
0721:                    if (pegRevision.isValid()) {
0722:                        SVNRepositoryLocation[] locations = getLocations(url1,
0723:                                null, null, pegRevision, revision1,
0724:                                SVNRevision.UNDEFINED);
0725:                        url1 = locations[0].getURL();
0726:                        String anchorPath2 = SVNPathUtil.append(anchorURL
0727:                                .toString(), target == null ? "" : target);
0728:                        getDiffGenerator().init(url1.toString(), anchorPath2);
0729:                    }
0730:                    SVNRepository repository = createRepository(anchorURL, true);
0731:                    long revNumber = getRevisionNumber(revision1, repository,
0732:                            null);
0733:                    AbstractDiffCallback callback = new SVNDiffCallback(info,
0734:                            getDiffGenerator(), reverse ? -1 : revNumber,
0735:                            reverse ? revNumber : -1, result);
0736:                    SVNDiffEditor editor = new SVNDiffEditor(
0737:                            wcAccess,
0738:                            info,
0739:                            callback,
0740:                            useAncestry,
0741:                            reverse /* reverse */,
0742:                            revision2 == SVNRevision.BASE
0743:                                    || revision2 == SVNRevision.COMMITTED /* compare to base */,
0744:                            recursive);
0745:                    SVNReporter reporter = new SVNReporter(info, info
0746:                            .getAnchor().getFile(info.getTargetName()), false,
0747:                            recursive, getDebugLog());
0748:
0749:                    long pegRevisionNumber = getRevisionNumber(revision2,
0750:                            repository, path2);
0751:                    try {
0752:                        repository.diff(url1, revNumber, pegRevisionNumber,
0753:                                target, !useAncestry, recursive, true,
0754:                                reporter, SVNCancellableEditor.newInstance(
0755:                                        editor, this , getDebugLog()));
0756:                    } finally {
0757:                        editor.cleanup();
0758:                    }
0759:                } finally {
0760:                    wcAccess.close();
0761:                }
0762:            }
0763:
0764:            private void doDiffURLWC(File path1, SVNRevision revision1,
0765:                    SVNRevision pegRevision, File path2, SVNRevision revision2,
0766:                    boolean reverse, boolean recursive, boolean useAncestry,
0767:                    OutputStream result) throws SVNException {
0768:
0769:                SVNWCAccess wcAccess = createWCAccess();
0770:                try {
0771:                    SVNAdminAreaInfo info = wcAccess.openAnchor(path2, false,
0772:                            recursive ? SVNWCAccess.INFINITE_DEPTH : 0);
0773:
0774:                    File anchorPath = info.getAnchor().getRoot();
0775:                    String target = "".equals(info.getTargetName()) ? null
0776:                            : info.getTargetName();
0777:
0778:                    SVNEntry anchorEntry = info.getAnchor().getEntry("", false);
0779:                    if (anchorEntry == null) {
0780:                        SVNErrorMessage err = SVNErrorMessage.create(
0781:                                SVNErrorCode.ENTRY_NOT_FOUND,
0782:                                "''{0}'' is not under version control",
0783:                                anchorPath);
0784:                        SVNErrorManager.error(err);
0785:                    } else if (anchorEntry.getURL() == null) {
0786:                        SVNErrorMessage err = SVNErrorMessage.create(
0787:                                SVNErrorCode.ENTRY_MISSING_URL,
0788:                                "''{0}'' has no URL", anchorPath);
0789:                        SVNErrorManager.error(err);
0790:                    }
0791:                    SVNURL url1;
0792:                    SVNURL anchorURL = anchorEntry.getSVNURL();
0793:                    if (pegRevision.isValid()) {
0794:                        SVNRepositoryLocation[] locations = getLocations(null,
0795:                                path1, null, pegRevision, revision1,
0796:                                SVNRevision.UNDEFINED);
0797:                        url1 = locations[0].getURL();
0798:                        String anchorPath2 = SVNPathUtil.append(anchorURL
0799:                                .toString(), target == null ? "" : target);
0800:                        if (!reverse) {
0801:                            getDiffGenerator().init(url1.toString(),
0802:                                    anchorPath2);
0803:                        } else {
0804:                            getDiffGenerator().init(anchorPath2,
0805:                                    url1.toString());
0806:                        }
0807:                    } else {
0808:                        url1 = getURL(path1);
0809:                    }
0810:                    SVNRepository repository = createRepository(anchorURL, true);
0811:                    long revNumber = getRevisionNumber(revision1, repository,
0812:                            path1);
0813:                    AbstractDiffCallback callback = new SVNDiffCallback(info,
0814:                            getDiffGenerator(), reverse ? -1 : revNumber,
0815:                            reverse ? revNumber : -1, result);
0816:                    SVNDiffEditor editor = new SVNDiffEditor(
0817:                            wcAccess,
0818:                            info,
0819:                            callback,
0820:                            useAncestry,
0821:                            reverse /* reverse */,
0822:                            revision2 == SVNRevision.BASE
0823:                                    || revision2 == SVNRevision.COMMITTED /* compare to base */,
0824:                            recursive);
0825:                    SVNReporter reporter = new SVNReporter(info, info
0826:                            .getAnchor().getFile(info.getTargetName()), false,
0827:                            recursive, getDebugLog());
0828:
0829:                    // this should be rev2.
0830:                    long pegRevisionNumber = getRevisionNumber(revision2,
0831:                            repository, path2);
0832:                    try {
0833:                        repository.diff(url1, revNumber, pegRevisionNumber,
0834:                                target, !useAncestry, recursive, true,
0835:                                reporter, SVNCancellableEditor.newInstance(
0836:                                        editor, this , getDebugLog()));
0837:                    } finally {
0838:                        editor.cleanup();
0839:                    }
0840:                } finally {
0841:                    wcAccess.close();
0842:                }
0843:            }
0844:
0845:            private void doDiffWCWC(File path1, SVNRevision revision1,
0846:                    File path2, SVNRevision revision2, boolean recursive,
0847:                    boolean useAncestry, OutputStream result)
0848:                    throws SVNException {
0849:                if (!path1.equals(path2)
0850:                        || !(revision1 == SVNRevision.BASE && revision2 == SVNRevision.WORKING)) {
0851:                    SVNErrorMessage err = SVNErrorMessage
0852:                            .create(
0853:                                    SVNErrorCode.UNSUPPORTED_FEATURE,
0854:                                    "Only diffs between a path's text-base "
0855:                                            + "and its working files are supported at this time (-rBASE:WORKING)");
0856:                    SVNErrorManager.error(err);
0857:                }
0858:
0859:                SVNWCAccess wcAccess = createWCAccess();
0860:                try {
0861:                    SVNAdminAreaInfo info = wcAccess.openAnchor(path1, false,
0862:                            recursive ? SVNWCAccess.INFINITE_DEPTH : 0);
0863:                    SVNEntry entry = wcAccess.getEntry(path1, false);
0864:                    if (entry == null) {
0865:                        SVNErrorMessage err = SVNErrorMessage.create(
0866:                                SVNErrorCode.ENTRY_NOT_FOUND,
0867:                                "''{0}'' is not under version control", path1);
0868:                        SVNErrorManager.error(err);
0869:                    }
0870:                    long rev = getRevisionNumber(revision1, null, path1);
0871:                    AbstractDiffCallback callback = new SVNDiffCallback(info,
0872:                            getDiffGenerator(), rev, -1, result);
0873:                    SVNDiffEditor editor = new SVNDiffEditor(wcAccess, info,
0874:                            callback, useAncestry, false, false, recursive);
0875:                    try {
0876:                        editor.closeEdit();
0877:                    } finally {
0878:                        editor.cleanup();
0879:                    }
0880:                } finally {
0881:                    wcAccess.close();
0882:                }
0883:            }
0884:
0885:            private void doDiffURLURL(SVNURL url1, File path1,
0886:                    SVNRevision revision1, SVNURL url2, File path2,
0887:                    SVNRevision revision2, SVNRevision pegRevision,
0888:                    boolean recursive, boolean useAncestry, OutputStream result)
0889:                    throws SVNException {
0890:                File basePath = null;
0891:                if (path1 != null) {
0892:                    basePath = path1;
0893:                }
0894:                if (path2 != null) {
0895:                    basePath = path2;
0896:                }
0897:                if (pegRevision.isValid()) {
0898:                    SVNRepositoryLocation[] locations = getLocations(url2,
0899:                            path2, null, pegRevision, revision1, revision2);
0900:                    url1 = locations[0].getURL();
0901:                    url2 = locations[1].getURL();
0902:
0903:                    getDiffGenerator().init(url1.toString(), url2.toString());
0904:                } else {
0905:                    url1 = url1 == null ? getURL(path1) : url1;
0906:                    url2 = url2 == null ? getURL(path2) : url2;
0907:                }
0908:                SVNRepository repository1 = createRepository(url1, true);
0909:                SVNRepository repository2 = createRepository(url2, false);
0910:
0911:                final long rev1 = getRevisionNumber(revision1, repository1,
0912:                        path1);
0913:                long rev2 = -1;
0914:                String target1 = null;
0915:                SVNNodeKind kind1 = null;
0916:                SVNNodeKind kind2 = null;
0917:                try {
0918:                    rev2 = getRevisionNumber(revision2, repository2, path2);
0919:                    kind1 = repository1.checkPath("", rev1);
0920:                    kind2 = repository2.checkPath("", rev2);
0921:                    if (kind1 == SVNNodeKind.NONE) {
0922:                        SVNErrorMessage err = SVNErrorMessage
0923:                                .create(
0924:                                        SVNErrorCode.FS_NOT_FOUND,
0925:                                        "''{0}'' was not found in the repository at revision {1}",
0926:                                        new Object[] { url1, new Long(rev1) });
0927:                        SVNErrorManager.error(err);
0928:                    } else if (kind2 == SVNNodeKind.NONE) {
0929:                        SVNErrorMessage err = SVNErrorMessage
0930:                                .create(
0931:                                        SVNErrorCode.FS_NOT_FOUND,
0932:                                        "''{0}'' was not found in the repository at revision {1}",
0933:                                        new Object[] { url2, new Long(rev2) });
0934:                        SVNErrorManager.error(err);
0935:                    }
0936:                } finally {
0937:                    repository2.closeSession();
0938:                }
0939:                if (kind1 == SVNNodeKind.FILE || kind2 == SVNNodeKind.FILE) {
0940:                    target1 = SVNPathUtil.tail(url1.getPath());
0941:                    if (basePath != null) {
0942:                        basePath = basePath.getParentFile();
0943:                    }
0944:                    url1 = SVNURL.parseURIEncoded(SVNPathUtil.removeTail(url1
0945:                            .toString()));
0946:                    repository1 = createRepository(url1, true);
0947:                }
0948:                repository2 = createRepository(url1, false);
0949:                SVNRemoteDiffEditor editor = null;
0950:                try {
0951:                    SVNDiffCallback callback = new SVNDiffCallback(null,
0952:                            getDiffGenerator(), rev1, rev2, result);
0953:                    callback.setBasePath(basePath);
0954:                    editor = new SVNRemoteDiffEditor(null, null, callback,
0955:                            repository2, rev1, rev2, false, null, this );
0956:                    ISVNReporterBaton reporter = new ISVNReporterBaton() {
0957:                        public void report(ISVNReporter reporter)
0958:                                throws SVNException {
0959:                            reporter.setPath("", null, rev1, false);
0960:                            reporter.finishReport();
0961:                        }
0962:                    };
0963:                    repository1.diff(url2, rev2, rev1, target1, !useAncestry,
0964:                            recursive, true, reporter, SVNCancellableEditor
0965:                                    .newInstance(editor, this , getDebugLog()));
0966:                } finally {
0967:                    if (editor != null) {
0968:                        editor.cleanup();
0969:                    }
0970:                    repository2.closeSession();
0971:                }
0972:            }
0973:
0974:            private void doDiffURLURL(SVNURL url1, File path1,
0975:                    SVNRevision revision1, SVNURL url2, File path2,
0976:                    SVNRevision revision2, SVNRevision pegRevision,
0977:                    boolean recursive, boolean useAncestry,
0978:                    ISVNDiffStatusHandler handler) throws SVNException {
0979:                File basePath = null;
0980:                if (path1 != null) {
0981:                    basePath = path1;
0982:                }
0983:                if (path2 != null) {
0984:                    basePath = path2;
0985:                }
0986:                if (pegRevision.isValid()) {
0987:                    SVNRepositoryLocation[] locations = getLocations(url2,
0988:                            path2, null, pegRevision, revision1, revision2);
0989:                    url1 = locations[0].getURL();
0990:                    url2 = locations[1].getURL();
0991:
0992:                    getDiffGenerator().init(url1.toString(), url2.toString());
0993:                } else {
0994:                    url1 = url1 == null ? getURL(path1) : url1;
0995:                    url2 = url2 == null ? getURL(path2) : url2;
0996:                }
0997:                SVNRepository repository1 = createRepository(url1, true);
0998:                SVNRepository repository2 = createRepository(url2, false);
0999:
1000:                final long rev1 = getRevisionNumber(revision1, repository1,
1001:                        path1);
1002:                long rev2 = -1;
1003:                SVNNodeKind kind1 = null;
1004:                SVNNodeKind kind2 = null;
1005:                String target1 = null;
1006:
1007:                try {
1008:                    rev2 = getRevisionNumber(revision2, repository2, path2);
1009:
1010:                    kind1 = repository1.checkPath("", rev1);
1011:                    kind2 = repository2.checkPath("", rev2);
1012:                    if (kind1 == SVNNodeKind.NONE) {
1013:                        SVNErrorMessage err = SVNErrorMessage
1014:                                .create(
1015:                                        SVNErrorCode.FS_NOT_FOUND,
1016:                                        "''{0}'' was not found in the repository at revision {1}",
1017:                                        new Object[] { url1, new Long(rev1) });
1018:                        SVNErrorManager.error(err);
1019:                    } else if (kind2 == SVNNodeKind.NONE) {
1020:                        SVNErrorMessage err = SVNErrorMessage
1021:                                .create(
1022:                                        SVNErrorCode.FS_NOT_FOUND,
1023:                                        "''{0}'' was not found in the repository at revision {1}",
1024:                                        new Object[] { url2, new Long(rev2) });
1025:                        SVNErrorManager.error(err);
1026:                    }
1027:                    if (kind1 == SVNNodeKind.FILE || kind2 == SVNNodeKind.FILE) {
1028:                        target1 = SVNPathUtil.tail(url1.getPath());
1029:                        if (basePath != null) {
1030:                            basePath = basePath.getParentFile();
1031:                        }
1032:                        url1 = SVNURL.parseURIEncoded(SVNPathUtil
1033:                                .removeTail(url1.toString()));
1034:                        repository1 = createRepository(url1, true);
1035:                    }
1036:                } finally {
1037:                    repository2.closeSession();
1038:                }
1039:                repository2 = createRepository(url1, false);
1040:                File tmpFile = getDiffGenerator().createTempDirectory();
1041:                try {
1042:                    SVNDiffStatusEditor editor = new SVNDiffStatusEditor(
1043:                            basePath, repository2, rev1, handler);
1044:                    ISVNReporterBaton reporter = new ISVNReporterBaton() {
1045:                        public void report(ISVNReporter reporter)
1046:                                throws SVNException {
1047:                            reporter.setPath("", null, rev1, false);
1048:                            reporter.finishReport();
1049:                        }
1050:                    };
1051:                    repository1.diff(url2, rev2, rev1, target1, !useAncestry,
1052:                            recursive, false, reporter, SVNCancellableEditor
1053:                                    .newInstance(editor, this , getDebugLog()));
1054:                } finally {
1055:                    if (tmpFile != null) {
1056:                        SVNFileUtil.deleteAll(tmpFile, true, null);
1057:                    }
1058:                    repository2.closeSession();
1059:                }
1060:            }
1061:
1062:            /**
1063:             * Applies the differences between two sources (using Working Copy paths to 
1064:             * get corresponding URLs of the sources) to a Working Copy path.
1065:             *
1066:             * <p>
1067:             * Corresponds to the SVN command line client's 
1068:             * <code>'svn merge sourceWCPATH1@rev1 sourceWCPATH2@rev2 WCPATH'</code> command.
1069:             * 
1070:             * <p>
1071:             * If you need only to try merging your file(s) without actual merging, you
1072:             * should set <code>dryRun</code> to <span class="javakeyword">true</span>.
1073:             * Your event handler will be dispatched status type information on the target 
1074:             * path(s). If a path can be successfully merged, the status type will be
1075:             * {@link SVNStatusType#MERGED} for that path.  
1076:             * 
1077:             * @param  path1          the first source path
1078:             * @param  revision1      a revision of <code>path1</code>
1079:             * @param  path2          the second source path which URL is to be compared
1080:             *                        against the URL of <code>path1</code>
1081:             * @param  revision2      a revision of <code>path2</code>
1082:             * @param  dstPath        the target path to which the result should
1083:             *                        be applied 
1084:             * @param  recusrsive     <span class="javakeyword">true</span> to descend 
1085:             *                        recursively
1086:             * @param  useAncestry    if <span class="javakeyword">true</span> then
1087:             *                        the paths ancestry will be noticed while calculating differences,
1088:             *                        otherwise not
1089:             * @param  force          <span class="javakeyword">true</span> to
1090:             *                        force the operation to run
1091:             * @param  dryRun         if <span class="javakeyword">true</span> then
1092:             *                        only tries the operation to run (to find out
1093:             *                        if a file can be merged successfully)
1094:             * @throws SVNException   if one of the following is true:
1095:             *                        <ul>
1096:             *                        <li>at least one of <code>revision1</code> and <code>revision2</code> is
1097:             *                        invalid
1098:             *                        <li><code>path1</code> has no URL
1099:             *                        <li><code>path2</code> has no URL
1100:             *                        <li>the repository location of <code>path1</code> was 
1101:             *                        not found in <code>revision1</code>
1102:             *                        <li>the repository location of <code>path2</code> was 
1103:             *                        not found in <code>revision2</code>
1104:             *                        <li><code>dstPath</code> is not under version control
1105:             *                        </ul>
1106:             */
1107:            public void doMerge(File path1, SVNRevision revision1, File path2,
1108:                    SVNRevision revision2, File dstPath, boolean recusrsive,
1109:                    boolean useAncestry, boolean force, boolean dryRun)
1110:                    throws SVNException {
1111:                path1 = new File(SVNPathUtil.validateFilePath(path1
1112:                        .getAbsolutePath())).getAbsoluteFile();
1113:                path2 = new File(SVNPathUtil.validateFilePath(path2
1114:                        .getAbsolutePath())).getAbsoluteFile();
1115:                dstPath = new File(SVNPathUtil.validateFilePath(dstPath
1116:                        .getAbsolutePath())).getAbsoluteFile();
1117:                /*
1118:                 * Same as 2. merge sourceWCPATH1@N sourceWCPATH2@M [WCPATH]
1119:                 * or      3. merge -r N:M SOURCE[@REV] [WCPATH]
1120:                 * where SOURCE is a path and path1 and path2 are the same.
1121:                 */
1122:                SVNRevision pegRevision = SVNRevision.UNDEFINED;
1123:                if (path1.equals(path2)) {
1124:                    pegRevision = SVNRevision.WORKING;
1125:                }
1126:                SVNURL url1 = getURL(path1);
1127:                if (url1 == null) {
1128:                    SVNErrorMessage err = SVNErrorMessage.create(
1129:                            SVNErrorCode.ENTRY_MISSING_URL,
1130:                            "''{0}'' has no URL", path1);
1131:                    SVNErrorManager.error(err);
1132:                }
1133:                SVNURL url2 = getURL(path2);
1134:                if (url2 == null) {
1135:                    SVNErrorMessage err = SVNErrorMessage.create(
1136:                            SVNErrorCode.ENTRY_MISSING_URL,
1137:                            "''{0}'' has no URL", path2);
1138:                    SVNErrorManager.error(err);
1139:                }
1140:                SVNWCAccess wcAccess = createWCAccess();
1141:                dstPath = new File(SVNPathUtil.validateFilePath(dstPath
1142:                        .getAbsolutePath()));
1143:                try {
1144:                    dstPath = new File(SVNPathUtil.validateFilePath(dstPath
1145:                            .getAbsolutePath()));
1146:                    SVNAdminAreaInfo info = wcAccess.openAnchor(dstPath,
1147:                            !dryRun, recusrsive ? SVNWCAccess.INFINITE_DEPTH
1148:                                    : 0);
1149:
1150:                    SVNEntry targetEntry = wcAccess.getEntry(dstPath, false);
1151:                    if (targetEntry == null) {
1152:                        SVNErrorMessage err = SVNErrorMessage
1153:                                .create(SVNErrorCode.ENTRY_NOT_FOUND,
1154:                                        "''{0}'' is not under version control",
1155:                                        dstPath);
1156:                        SVNErrorManager.error(err);
1157:                    }
1158:                    if (targetEntry.isFile()) {
1159:                        doMergeFile(url1, path1, revision1, url2, path2,
1160:                                revision2, pegRevision, info, force, dryRun);
1161:                    } else if (targetEntry.isDirectory()) {
1162:                        doMerge(url1, path1, revision1, url2, path2, revision2,
1163:                                pegRevision, info, recusrsive, useAncestry,
1164:                                force, dryRun);
1165:                    }
1166:                } finally {
1167:                    wcAccess.close();
1168:                }
1169:            }
1170:
1171:            /**
1172:             * Applies the differences between two sources (a source URL against the 
1173:             * repository location URL of a source Working Copy path) to a Working Copy 
1174:             * path.
1175:             * 
1176:             * <p>
1177:             * If you need only to try merging your file(s) without actual merging, you
1178:             * should set <code>dryRun</code> to <span class="javakeyword">true</span>.
1179:             * Your event handler will be dispatched status type information on the target 
1180:             * path(s). If a path can be successfully merged, the status type will be
1181:             * {@link SVNStatusType#MERGED} for that path.  
1182:             * 
1183:             * @param  path1          the first source - a WC path 
1184:             * @param  revision1      a revision of <code>path1</code>
1185:             * @param  url2           the second source - a URL that is to be compared 
1186:             *                        against the URL of <code>path1</code>
1187:             * @param  revision2      a revision of <code>url2</code>
1188:             * @param  dstPath        the target path to which the result should
1189:             *                        be applied
1190:             * @param  recusrsive     <span class="javakeyword">true</span> to descend 
1191:             *                        recursively
1192:             * @param  useAncestry    if <span class="javakeyword">true</span> then
1193:             *                        the paths ancestry will be noticed while calculating differences,
1194:             *                        otherwise not
1195:             * @param  force          <span class="javakeyword">true</span> to
1196:             *                        force the operation to run
1197:             * @param  dryRun         if <span class="javakeyword">true</span> then
1198:             *                        only tries the operation to run (to find out
1199:             *                        if a file can be merged successfully)
1200:             * @throws SVNException   if one of the following is true:
1201:             *                        <ul>
1202:             *                        <li>at least one of <code>revision1</code> and <code>revision2</code> is
1203:             *                        invalid
1204:             *                        <li><code>path1</code> has no URL
1205:             *                        <li>the repository location of <code>path1</code> was 
1206:             *                        not found in <code>revision1</code>
1207:             *                        <li><code>url2</code> was not found in 
1208:             *                        <code>revision2</code>
1209:             *                        <li><code>dstPath</code> is not under version control
1210:             *                        </ul>
1211:             */
1212:            public void doMerge(File path1, SVNRevision revision1, SVNURL url2,
1213:                    SVNRevision revision2, File dstPath, boolean recusrsive,
1214:                    boolean useAncestry, boolean force, boolean dryRun)
1215:                    throws SVNException {
1216:                path1 = new File(SVNPathUtil.validateFilePath(path1
1217:                        .getAbsolutePath())).getAbsoluteFile();
1218:                dstPath = new File(SVNPathUtil.validateFilePath(dstPath
1219:                        .getAbsolutePath())).getAbsoluteFile();
1220:                SVNURL url1 = getURL(path1);
1221:                if (url1 == null) {
1222:                    SVNErrorMessage err = SVNErrorMessage.create(
1223:                            SVNErrorCode.ENTRY_MISSING_URL,
1224:                            "''{0}'' has no URL", path1);
1225:                    SVNErrorManager.error(err);
1226:                }
1227:                SVNRevision pegRevision = SVNRevision.UNDEFINED;
1228:                if (url1.equals(url2)) {
1229:                    pegRevision = SVNRevision.HEAD;
1230:                }
1231:                SVNWCAccess wcAccess = createWCAccess();
1232:                try {
1233:                    dstPath = new File(SVNPathUtil.validateFilePath(dstPath
1234:                            .getAbsolutePath()));
1235:                    SVNAdminAreaInfo info = wcAccess.openAnchor(dstPath,
1236:                            !dryRun, recusrsive ? SVNWCAccess.INFINITE_DEPTH
1237:                                    : 0);
1238:
1239:                    SVNEntry targetEntry = wcAccess.getEntry(dstPath, false);
1240:                    if (targetEntry == null) {
1241:                        SVNErrorMessage err = SVNErrorMessage
1242:                                .create(SVNErrorCode.ENTRY_NOT_FOUND,
1243:                                        "''{0}'' is not under version control",
1244:                                        dstPath);
1245:                        SVNErrorManager.error(err);
1246:                    }
1247:                    if (targetEntry.isFile()) {
1248:                        doMergeFile(url1, path1, revision1, url2, null,
1249:                                revision2, pegRevision, info, force, dryRun);
1250:                    } else if (targetEntry.isDirectory()) {
1251:                        doMerge(url1, path1, revision1, url2, null, revision2,
1252:                                pegRevision, info, recusrsive, useAncestry,
1253:                                force, dryRun);
1254:                    }
1255:                } finally {
1256:                    wcAccess.close();
1257:                }
1258:            }
1259:
1260:            /**
1261:             * Applies the differences between two sources (the repository location URL of 
1262:             * a source Working Copy against a source URL) to a Working Copy path.
1263:             * 
1264:             * <p>
1265:             * If you need only to try merging your file(s) without actual merging, you
1266:             * should set <code>dryRun</code> to <span class="javakeyword">true</span>.
1267:             * Your event handler will be dispatched status type information on the target 
1268:             * path(s). If a path can be successfully merged, the status type will be
1269:             * {@link SVNStatusType#MERGED} for that path.  
1270:             * 
1271:             * @param  url1           the first source - a URL
1272:             * @param  revision1      a revision of <code>url1</code>
1273:             * @param  path2          the second source - a WC path that is to be compared 
1274:             *                        against <code>url1</code>
1275:             * @param  revision2      a revision of <code>path2</code>
1276:             * @param  dstPath        the target path to which the result should
1277:             *                        be applied
1278:             * @param  recusrsive     <span class="javakeyword">true</span> to descend 
1279:             *                        recursively
1280:             * @param  useAncestry    if <span class="javakeyword">true</span> then
1281:             *                        the paths ancestry will be noticed while calculating differences,
1282:             *                        otherwise not
1283:             * @param  force          <span class="javakeyword">true</span> to
1284:             *                        force the operation to run
1285:             * @param  dryRun         if <span class="javakeyword">true</span> then
1286:             *                        only tries the operation to run (to find out
1287:             *                        if a file can be merged successfully)
1288:             * @throws SVNException   if one of the following is true:
1289:             *                        <ul>
1290:             *                        <li>at least one of <code>revision1</code> and <code>revision2</code> is
1291:             *                        invalid
1292:             *                        <li><code>path2</code> has no URL
1293:             *                        <li><code>url1</code> was not found in 
1294:             *                        <code>revision1</code>
1295:             *                        <li>the repository location of <code>path2</code> was 
1296:             *                        not found in <code>revision2</code>
1297:             *                        <li><code>dstPath</code> is not under version control
1298:             *                        </ul>
1299:             */
1300:            public void doMerge(SVNURL url1, SVNRevision revision1, File path2,
1301:                    SVNRevision revision2, File dstPath, boolean recusrsive,
1302:                    boolean useAncestry, boolean force, boolean dryRun)
1303:                    throws SVNException {
1304:                path2 = new File(SVNPathUtil.validateFilePath(path2
1305:                        .getAbsolutePath())).getAbsoluteFile();
1306:                dstPath = new File(SVNPathUtil.validateFilePath(dstPath
1307:                        .getAbsolutePath())).getAbsoluteFile();
1308:                SVNURL url2 = getURL(path2);
1309:                if (url2 == null) {
1310:                    SVNErrorMessage err = SVNErrorMessage.create(
1311:                            SVNErrorCode.ENTRY_MISSING_URL,
1312:                            "''{0}'' has no URL", path2);
1313:                    SVNErrorManager.error(err);
1314:                }
1315:                SVNRevision pegRevision = SVNRevision.UNDEFINED;
1316:                if (url1.equals(url2)) {
1317:                    pegRevision = SVNRevision.WORKING;
1318:                }
1319:                SVNWCAccess wcAccess = createWCAccess();
1320:                try {
1321:                    dstPath = new File(SVNPathUtil.validateFilePath(dstPath
1322:                            .getAbsolutePath()));
1323:                    SVNAdminAreaInfo info = wcAccess.openAnchor(dstPath,
1324:                            !dryRun, recusrsive ? SVNWCAccess.INFINITE_DEPTH
1325:                                    : 0);
1326:
1327:                    SVNEntry targetEntry = wcAccess.getEntry(dstPath, false);
1328:                    if (targetEntry == null) {
1329:                        SVNErrorMessage err = SVNErrorMessage
1330:                                .create(SVNErrorCode.ENTRY_NOT_FOUND,
1331:                                        "''{0}'' is not under version control",
1332:                                        dstPath);
1333:                        SVNErrorManager.error(err);
1334:                    }
1335:                    if (targetEntry.isFile()) {
1336:                        doMergeFile(url1, null, revision1, url2, path2,
1337:                                revision2, pegRevision, info, force, dryRun);
1338:                    } else if (targetEntry.isDirectory()) {
1339:                        doMerge(url1, null, revision1, url2, path2, revision2,
1340:                                pegRevision, info, recusrsive, useAncestry,
1341:                                force, dryRun);
1342:                    }
1343:                } finally {
1344:                    wcAccess.close();
1345:                }
1346:            }
1347:
1348:            /**
1349:             * Applies the differences between two sources (one source URL against another 
1350:             * source URL) to a Working Copy path.
1351:             *
1352:             * <p>
1353:             * Corresponds to the SVN command line client's 
1354:             * <code>'svn merge sourceURL1@rev1 sourceURL2@rev2 WCPATH'</code> command.
1355:             * 
1356:             * <p>
1357:             * If you need only to try merging your file(s) without actual merging, you
1358:             * should set <code>dryRun</code> to <span class="javakeyword">true</span>.
1359:             * Your event handler will be dispatched status type information on the target 
1360:             * path(s). If a path can be successfully merged, the status type will be
1361:             * {@link SVNStatusType#MERGED} for that path.  
1362:             * 
1363:             * @param  url1           the first source URL
1364:             * @param  revision1      a revision of <code>url1</code>
1365:             * @param  url2           the second source URL that is to be compared against 
1366:             *                        <code>url1</code>
1367:             * @param  revision2      a revision of <code>url2</code>
1368:             * @param  dstPath        the target path to which the result should
1369:             *                        be applied
1370:             * @param  recusrsive     <span class="javakeyword">true</span> to descend 
1371:             *                        recursively
1372:             * @param  useAncestry    if <span class="javakeyword">true</span> then
1373:             *                        the paths ancestry will be noticed while calculating differences,
1374:             *                        otherwise not
1375:             * @param  force          <span class="javakeyword">true</span> to
1376:             *                        force the operation to run
1377:             * @param  dryRun         if <span class="javakeyword">true</span> then
1378:             *                        only tries the operation to run (to find out
1379:             *                        if a file can be merged successfully)
1380:             * @throws SVNException   if one of the following is true:
1381:             *                        <ul>
1382:             *                        <li>at least one of <code>revision1</code> and <code>revision2</code> is
1383:             *                        invalid
1384:             *                        <li><code>url1</code> was not found in 
1385:             *                        <code>revision1</code>
1386:             *                        <li><code>url2</code> was not found in 
1387:             *                        <code>revision2</code>
1388:             *                        <li><code>dstPath</code> is not under version control
1389:             *                        </ul>
1390:             */
1391:            public void doMerge(SVNURL url1, SVNRevision revision1,
1392:                    SVNURL url2, SVNRevision revision2, File dstPath,
1393:                    boolean recusrsive, boolean useAncestry, boolean force,
1394:                    boolean dryRun) throws SVNException {
1395:                SVNRevision pegRevision = SVNRevision.UNDEFINED;
1396:                if (url1.equals(url2)) {
1397:                    pegRevision = SVNRevision.HEAD;
1398:                }
1399:                SVNWCAccess wcAccess = createWCAccess();
1400:                try {
1401:                    dstPath = new File(SVNPathUtil.validateFilePath(dstPath
1402:                            .getAbsolutePath())).getAbsoluteFile();
1403:                    SVNAdminAreaInfo info = wcAccess.openAnchor(dstPath,
1404:                            !dryRun, recusrsive ? SVNWCAccess.INFINITE_DEPTH
1405:                                    : 0);
1406:                    SVNEntry targetEntry = wcAccess.getEntry(dstPath, false);
1407:
1408:                    if (targetEntry == null) {
1409:                        SVNErrorMessage err = SVNErrorMessage
1410:                                .create(SVNErrorCode.ENTRY_NOT_FOUND,
1411:                                        "''{0}'' is not under version control",
1412:                                        dstPath);
1413:                        SVNErrorManager.error(err);
1414:                    }
1415:                    if (targetEntry.isFile()) {
1416:                        doMergeFile(url1, null, revision1, url2, null,
1417:                                revision2, pegRevision, info, force, dryRun);
1418:                    } else if (targetEntry.isDirectory()) {
1419:                        doMerge(url1, null, revision1, url2, null, revision2,
1420:                                pegRevision, info, recusrsive, useAncestry,
1421:                                force, dryRun);
1422:                    }
1423:                } finally {
1424:                    wcAccess.close();
1425:                }
1426:
1427:            }
1428:
1429:            /**
1430:             * Applies the differences between two sources (a source URL in a particular
1431:             * revision against the same source URL in another particular revision) to a 
1432:             * Working Copy path.
1433:             * 
1434:             * <p>
1435:             * Corresponds to the SVN command line client's 
1436:             * <code>'svn merge -r rev1:rev2 URL@pegRev WCPATH'</code> command.
1437:             * 
1438:             * <p>
1439:             * If you need only to try merging your file(s) without actual merging, you
1440:             * should set <code>dryRun</code> to <span class="javakeyword">true</span>.
1441:             * Your event handler will be dispatched status type information on the target 
1442:             * path(s). If a path can be successfully merged, the status type will be
1443:             * {@link SVNStatusType#MERGED} for that path.  
1444:             * 
1445:             * @param  url1           a source URL
1446:             * @param  pegRevision    a revision in which code>url1</code> 
1447:             *                        is first looked up
1448:             * @param  revision1      a left-hand revision of <code>url1</code> 
1449:             * @param  revision2      a right-hand revision of <code>url1</code>
1450:             * @param  dstPath        the target path to which the result should
1451:             *                        be applied
1452:             * @param  recusrsive     <span class="javakeyword">true</span> to descend 
1453:             *                        recursively
1454:             * @param  useAncestry    if <span class="javakeyword">true</span> then
1455:             *                        the paths ancestry will be noticed while calculating differences,
1456:             *                        otherwise not
1457:             * @param  force          <span class="javakeyword">true</span> to
1458:             *                        force the operation to run
1459:             * @param  dryRun         if <span class="javakeyword">true</span> then
1460:             *                        only tries the operation to run (to find out
1461:             *                        if a file can be merged successfully)
1462:             * @throws SVNException   if one of the following is true:
1463:             *                        <ul>
1464:             *                        <li>at least one of <code>revision1</code>, <code>revision2</code> and
1465:             *                        <code>pegRevision</code> is invalid
1466:             *                        <li><code>url1</code> was not found in 
1467:             *                        <code>revision1</code>
1468:             *                        <li><code>url1</code> was not found in 
1469:             *                        <code>revision2</code>
1470:             *                        <li><code>dstPath</code> is not under version control
1471:             *                        </ul>
1472:             */
1473:            public void doMerge(SVNURL url1, SVNRevision pegRevision,
1474:                    SVNRevision revision1, SVNRevision revision2, File dstPath,
1475:                    boolean recusrsive, boolean useAncestry, boolean force,
1476:                    boolean dryRun) throws SVNException {
1477:                if (pegRevision == null || !pegRevision.isValid()) {
1478:                    pegRevision = SVNRevision.HEAD;
1479:                }
1480:                SVNWCAccess wcAccess = createWCAccess();
1481:                dstPath = new File(SVNPathUtil.validateFilePath(dstPath
1482:                        .getAbsolutePath())).getAbsoluteFile();
1483:                try {
1484:                    SVNAdminAreaInfo info = wcAccess.openAnchor(dstPath,
1485:                            !dryRun, recusrsive ? SVNWCAccess.INFINITE_DEPTH
1486:                                    : 0);
1487:
1488:                    SVNEntry targetEntry = wcAccess.getEntry(dstPath, false);
1489:                    if (targetEntry == null) {
1490:                        SVNErrorMessage err = SVNErrorMessage
1491:                                .create(SVNErrorCode.ENTRY_NOT_FOUND,
1492:                                        "''{0}'' is not under version control",
1493:                                        dstPath);
1494:                        SVNErrorManager.error(err);
1495:                    }
1496:                    if (targetEntry.isFile()) {
1497:                        doMergeFile(url1, null, revision1, url1, null,
1498:                                revision2, pegRevision, info, force, dryRun);
1499:                    } else if (targetEntry.isDirectory()) {
1500:                        doMerge(url1, null, revision1, url1, null, revision2,
1501:                                pegRevision, info, recusrsive, useAncestry,
1502:                                force, dryRun);
1503:                    }
1504:                } finally {
1505:                    wcAccess.close();
1506:                }
1507:            }
1508:
1509:            /**
1510:             * Applies the differences between two sources (the repository location of
1511:             * a source Working Copy path in a particular revision against the repository
1512:             * location of the same path in another particular revision) to a 
1513:             * Working Copy path.
1514:             * 
1515:             * <p>
1516:             * Corresponds to the SVN command line client's 
1517:             * <code>'svn merge -r rev1:rev2 sourceWCPATH@pegRev WCPATH'</code> command.
1518:             * 
1519:             * <p>
1520:             * If you need only to try merging your file(s) without actual merging, you
1521:             * should set <code>dryRun</code> to <span class="javakeyword">true</span>.
1522:             * Your event handler will be dispatched status type information on the target 
1523:             * path(s). If a path can be successfully merged, the status type will be
1524:             * {@link SVNStatusType#MERGED} for that path.  
1525:             * 
1526:             * @param  path1          a source WC path
1527:             * @param  pegRevision    a revision in which the repository location of 
1528:             *                        <code>path1</code> is first looked up
1529:             * @param  revision1      a left-hand revision of <code>path1</code> 
1530:             * @param  revision2      a right-hand revision of <code>path1</code>
1531:             * @param  dstPath        the target path to which the result should
1532:             *                        be applied
1533:             * @param  recusrsive     <span class="javakeyword">true</span> to descend 
1534:             *                        recursively
1535:             * @param  useAncestry    if <span class="javakeyword">true</span> then
1536:             *                        the paths ancestry will be noticed while calculating differences,
1537:             *                        otherwise not
1538:             * @param  force          <span class="javakeyword">true</span> to
1539:             *                        force the operation to run
1540:             * @param  dryRun         if <span class="javakeyword">true</span> then
1541:             *                        only tries the operation to run (to find out
1542:             *                        if a file can be merged successfully)
1543:             * @throws SVNException   if one of the following is true:
1544:             *                        <ul>
1545:             *                        <li>at least one of <code>revision1</code>, <code>revision2</code> and
1546:             *                        <code>pegRevision</code> is invalid
1547:             *                        <li><code>path1</code> has no URL
1548:             *                        <li>the repository location of <code>path1</code> was not found in 
1549:             *                        <code>revision1</code>
1550:             *                        <li>the repository location of <code>path1</code> was not found in 
1551:             *                        <code>revision2</code>
1552:             *                        <li><code>dstPath</code> is not under version control
1553:             *                        </ul>
1554:             */
1555:            public void doMerge(File path1, SVNRevision pegRevision,
1556:                    SVNRevision revision1, SVNRevision revision2, File dstPath,
1557:                    boolean recusrsive, boolean useAncestry, boolean force,
1558:                    boolean dryRun) throws SVNException {
1559:                SVNURL url1 = getURL(path1);
1560:                if (url1 == null) {
1561:                    SVNErrorMessage err = SVNErrorMessage.create(
1562:                            SVNErrorCode.ENTRY_MISSING_URL,
1563:                            "''{0}'' has no URL", path1);
1564:                    SVNErrorManager.error(err);
1565:                }
1566:                /*
1567:                 * Equivalent of 3. merge -r N:M SOURCE[@REV] [WCPATH]
1568:                 * where SOURCE is a wc path.
1569:                 */
1570:                if (pegRevision == null || !pegRevision.isValid()) {
1571:                    pegRevision = SVNRevision.WORKING;
1572:                }
1573:                SVNWCAccess wcAccess = createWCAccess();
1574:                try {
1575:                    dstPath = new File(SVNPathUtil.validateFilePath(dstPath
1576:                            .getAbsolutePath())).getAbsoluteFile();
1577:                    path1 = new File(SVNPathUtil.validateFilePath(path1
1578:                            .getAbsolutePath())).getAbsoluteFile();
1579:                    SVNAdminAreaInfo info = wcAccess.openAnchor(dstPath
1580:                            .getAbsoluteFile(), !dryRun,
1581:                            recusrsive ? SVNWCAccess.INFINITE_DEPTH : 0);
1582:
1583:                    SVNEntry targetEntry = wcAccess.getEntry(dstPath, false);
1584:                    if (targetEntry == null) {
1585:                        SVNErrorMessage err = SVNErrorMessage
1586:                                .create(SVNErrorCode.ENTRY_NOT_FOUND,
1587:                                        "''{0}'' is not under version control",
1588:                                        dstPath);
1589:                        SVNErrorManager.error(err);
1590:                    }
1591:                    if (targetEntry.isFile()) {
1592:                        doMergeFile(url1, path1.getAbsoluteFile(), revision1,
1593:                                url1, path1.getAbsoluteFile(), revision2,
1594:                                pegRevision, info, force, dryRun);
1595:                    } else if (targetEntry.isDirectory()) {
1596:                        doMerge(url1, path1.getAbsoluteFile(), revision1, url1,
1597:                                path1.getAbsoluteFile(), revision2,
1598:                                pegRevision, info, recusrsive, useAncestry,
1599:                                force, dryRun);
1600:                    }
1601:                } finally {
1602:                    wcAccess.close();
1603:                }
1604:            }
1605:
1606:            private void doMerge(SVNURL url1, File path1,
1607:                    SVNRevision revision1, SVNURL url2, File path2,
1608:                    SVNRevision revision2, SVNRevision pegRevision,
1609:                    SVNAdminAreaInfo info, boolean recursive,
1610:                    boolean useAncestry, boolean force, boolean dryRun)
1611:                    throws SVNException {
1612:                if (!revision1.isValid() || !revision2.isValid()) {
1613:                    SVNErrorMessage err = SVNErrorMessage.create(
1614:                            SVNErrorCode.CLIENT_BAD_REVISION,
1615:                            "Both rN and rM revisions should be specified");
1616:                    SVNErrorManager.error(err);
1617:                }
1618:                if (pegRevision.isValid()) {
1619:                    SVNRepositoryLocation[] locations = getLocations(url2,
1620:                            path2, null, pegRevision, revision1, revision2);
1621:                    url1 = locations[0].getURL();
1622:                    url2 = locations[1].getURL();
1623:                    revision1 = SVNRevision.create(locations[0]
1624:                            .getRevisionNumber());
1625:                    revision2 = SVNRevision.create(locations[1]
1626:                            .getRevisionNumber());
1627:                    path1 = null;
1628:                    path2 = null;
1629:                }
1630:                SVNRepository repository1 = createRepository(url1, true);
1631:                final long rev1 = getRevisionNumber(revision1, repository1,
1632:                        path1);
1633:                long rev2 = getRevisionNumber(revision2, repository1, path2);
1634:                SVNRepository repository2 = createRepository(url1, false);
1635:
1636:                SVNMergeCallback callback = new SVNMergeCallback(info, url2,
1637:                        force, dryRun, getMergeOptions());
1638:                SVNRemoteDiffEditor editor = new SVNRemoteDiffEditor(info, info
1639:                        .getTarget().getRoot(), callback, repository2, rev1,
1640:                        rev2, dryRun, this , this );
1641:
1642:                try {
1643:                    repository1.diff(url2, rev2, rev1, null, !useAncestry,
1644:                            recursive, true, new ISVNReporterBaton() {
1645:                                public void report(ISVNReporter reporter)
1646:                                        throws SVNException {
1647:                                    reporter.setPath("", null, rev1, false);
1648:                                    reporter.finishReport();
1649:                                }
1650:                            }, SVNCancellableEditor.newInstance(editor, this ,
1651:                                    getDebugLog()));
1652:                } finally {
1653:                    editor.cleanup();
1654:                    repository2.closeSession();
1655:                }
1656:
1657:            }
1658:
1659:            private void doMergeFile(SVNURL url1, File path1,
1660:                    SVNRevision revision1, SVNURL url2, File path2,
1661:                    SVNRevision revision2, SVNRevision pegRevision,
1662:                    SVNAdminAreaInfo info, boolean force, boolean dryRun)
1663:                    throws SVNException {
1664:                if (pegRevision.isValid()) {
1665:                    SVNRepositoryLocation[] locations = getLocations(url2,
1666:                            path2, null, pegRevision, revision1, revision2);
1667:                    url1 = locations[0].getURL();
1668:                    url2 = locations[1].getURL();
1669:                    revision1 = SVNRevision.create(locations[0]
1670:                            .getRevisionNumber());
1671:                    revision2 = SVNRevision.create(locations[1]
1672:                            .getRevisionNumber());
1673:                    path1 = null;
1674:                    path2 = null;
1675:                }
1676:                long[] rev1 = new long[1];
1677:                long[] rev2 = new long[2];
1678:                Map props1 = new HashMap();
1679:                Map props2 = new HashMap();
1680:                File f1 = null;
1681:                File f2 = null;
1682:                String name = info.getTargetName();
1683:                String mimeType2;
1684:                String mimeType1;
1685:                SVNStatusType[] mergeResult;
1686:                try {
1687:                    f1 = loadFile(url1, path1, revision1, props1, info, rev1);
1688:                    f2 = loadFile(url2, path2, revision2, props2, info, rev2);
1689:
1690:                    mimeType1 = (String) props1.get(SVNProperty.MIME_TYPE);
1691:                    mimeType2 = (String) props2.get(SVNProperty.MIME_TYPE);
1692:                    props1 = filterProperties(props1, true, false, false);
1693:                    props2 = filterProperties(props2, true, false, false);
1694:                    Map propsDiff = computePropsDiff(props1, props2);
1695:                    // remove non wc props from props1.
1696:                    for (Iterator names = props1.keySet().iterator(); names
1697:                            .hasNext();) {
1698:                        String propertyName = (String) names.next();
1699:                        if (propertyName
1700:                                .startsWith(SVNProperty.SVN_ENTRY_PREFIX)
1701:                                || propertyName
1702:                                        .startsWith(SVNProperty.SVN_WC_PREFIX)) {
1703:                            names.remove();
1704:                        }
1705:                    }
1706:                    SVNMergeCallback callback = new SVNMergeCallback(info,
1707:                            url2, force, dryRun, getMergeOptions());
1708:                    mergeResult = callback.fileChanged(name, f1, f2, rev1[0],
1709:                            rev2[0], mimeType1, mimeType2, props1, propsDiff);
1710:                } finally {
1711:                    SVNFileUtil.deleteAll(f1, null);
1712:                    SVNFileUtil.deleteAll(f2, null);
1713:                }
1714:                handleEvent(SVNEventFactory.createUpdateModifiedEvent(info,
1715:                        info.getAnchor(), name, SVNNodeKind.FILE,
1716:                        SVNEventAction.UPDATE_UPDATE, mimeType2,
1717:                        mergeResult[0], mergeResult[1],
1718:                        SVNStatusType.LOCK_INAPPLICABLE),
1719:                        ISVNEventHandler.UNKNOWN);
1720:            }
1721:
1722:            private File loadFile(SVNURL url, File path, SVNRevision revision,
1723:                    Map properties, SVNAdminAreaInfo info, long[] revNumber)
1724:                    throws SVNException {
1725:                File tmpDir = info.getAnchor().getRoot();
1726:                File result = SVNFileUtil.createUniqueFile(tmpDir, ".merge",
1727:                        ".tmp");
1728:                SVNFileUtil.createEmptyFile(result);
1729:
1730:                SVNRepository repository = createRepository(url, true);
1731:                long revisionNumber = getRevisionNumber(revision, repository,
1732:                        path);
1733:                OutputStream os = null;
1734:                try {
1735:                    os = SVNFileUtil.openFileForWriting(result);
1736:                    repository.getFile("", revisionNumber, properties,
1737:                            new SVNCancellableOutputStream(os, this ));
1738:                } finally {
1739:                    SVNFileUtil.closeFile(os);
1740:                }
1741:                if (revNumber != null && revNumber.length > 0) {
1742:                    revNumber[0] = revisionNumber;
1743:                }
1744:                return result;
1745:            }
1746:
1747:            private static Map computePropsDiff(Map props1, Map props2) {
1748:                Map propsDiff = new HashMap();
1749:                for (Iterator names = props2.keySet().iterator(); names
1750:                        .hasNext();) {
1751:                    String newPropName = (String) names.next();
1752:                    if (props1.containsKey(newPropName)) {
1753:                        // changed.
1754:                        Object oldValue = props2.get(newPropName);
1755:                        if (!oldValue.equals(props1.get(newPropName))) {
1756:                            propsDiff.put(newPropName, props2.get(newPropName));
1757:                        }
1758:                    } else {
1759:                        // added.
1760:                        propsDiff.put(newPropName, props2.get(newPropName));
1761:                    }
1762:                }
1763:                for (Iterator names = props1.keySet().iterator(); names
1764:                        .hasNext();) {
1765:                    String oldPropName = (String) names.next();
1766:                    if (!props2.containsKey(oldPropName)) {
1767:                        // deleted
1768:                        propsDiff.put(oldPropName, null);
1769:                    }
1770:                }
1771:                return propsDiff;
1772:            }
1773:
1774:            private static Map filterProperties(Map props1,
1775:                    boolean leftRegular, boolean leftEntry, boolean leftWC) {
1776:                Map result = new HashMap();
1777:                for (Iterator names = props1.keySet().iterator(); names
1778:                        .hasNext();) {
1779:                    String propName = (String) names.next();
1780:                    if (!leftEntry
1781:                            && propName
1782:                                    .startsWith(SVNProperty.SVN_ENTRY_PREFIX)) {
1783:                        continue;
1784:                    }
1785:                    if (!leftWC
1786:                            && propName.startsWith(SVNProperty.SVN_WC_PREFIX)) {
1787:                        continue;
1788:                    }
1789:                    if (!leftRegular
1790:                            && !(propName
1791:                                    .startsWith(SVNProperty.SVN_ENTRY_PREFIX) || propName
1792:                                    .startsWith(SVNProperty.SVN_WC_PREFIX))) {
1793:                        continue;
1794:                    }
1795:                    result.put(propName, props1.get(propName));
1796:                }
1797:                return result;
1798:            }
1799:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.