git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@277673 13f79535-47bb-0310-9956-ffa450edef68master
@@ -100,7 +100,7 @@ illustrates how to generate a HTML report from the XML report.</p> | |||
<pre> | |||
<style in="diff.xml" | |||
out="diff.html" | |||
style="your-path-to/etc/revisiondiff.xsl"> | |||
style="your-path-to/etc/diff.xsl"> | |||
<param name="title" expression="Jakarta BCEL diff"/> | |||
<param name="repo" expression="http://svn.apache.org/repos/asf/jakarta/bcel/trunk"/> | |||
</style> | |||
@@ -0,0 +1,158 @@ | |||
<html> | |||
<head> | |||
<meta http-equiv="Content-Language" content="en-us"> | |||
<title>RevisionDiff Task</title> | |||
</head> | |||
<body> | |||
<h2><a name="tagdiff">TagDiff</a></h2> | |||
<h3>Description</h3> | |||
<p>Generates an XML-formatted report file of the changes between two | |||
tags recorded in a <a href="http://subversion.tigris.org/" | |||
target="_top">Subversion</a> repository. </p> | |||
<p><b>Important:</b> This task needs "svn" on the path. If it isn't, | |||
you will get an error (such as error 2 on windows). If | |||
<code><svn></code> doesn't work, try to execute | |||
<code>svn.exe</code> from the command line in the target directory in | |||
which you are working.</p> | |||
<p>This task assumes that your repository follows the best-practice | |||
layout of</p> | |||
<pre> | |||
BASEURL | |||
| | |||
| | |||
-----> trunk | |||
-----> tags | |||
| | |||
| | |||
----------> tag1 | |||
----------> tag2 | |||
</pre> | |||
<h3>Parameters</h3> | |||
<table border="1" cellpadding="2" cellspacing="0"> | |||
<tr> | |||
<td valign="top"><b>Attribute</b></td> | |||
<td valign="top"><b>Description</b></td> | |||
<td align="center" valign="top"><b>Required</b></td> | |||
</tr> | |||
<tr> | |||
<td valign="top">tag1</td> | |||
<td valign="top">The first tag.</td> | |||
<td align="center" valign="top">Yes.</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">tag2</td> | |||
<td valign="top">The second tag.</td> | |||
<td align="center" valign="top">No, defaults to "trunk/"</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">destfile</td> | |||
<td valign="top">The file in which to write the diff report.</td> | |||
<td align="center" valign="top">Yes</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">baseURL</td> | |||
<td valign="top">The baseURL of the repository, used to calculate | |||
the two URLs to compare.</td> | |||
<td align="center" valign="top">Yes</td> | |||
</tr> | |||
</table> | |||
<h3>Parameters inherited from the <code>svn</code> task</h3> | |||
<table border="1" cellpadding="2" cellspacing="0"> | |||
<tr> | |||
<td valign="top"><b>Attribute</b></td> | |||
<td valign="top"><b>Description</b></td> | |||
<td align="center" valign="top"><b>Required</b></td> | |||
</tr> | |||
<tr> | |||
<td valign="top">failonerror</td> | |||
<td valign="top">Stop the buildprocess if the command exits with a | |||
returncode other than 0. Defaults to false</td> | |||
<td align="center" valign="top">No</td> | |||
</tr> | |||
</table> | |||
<h3>Examples</h3> | |||
<pre> | |||
<tagdiff failonerror="true" | |||
baseURL="http://svn.apache.org/repos/asf/jakarta/bcel/" | |||
destfile="diff.xml" | |||
tag1="initial" | |||
tag2="BCEL_5_0" | |||
/> | |||
</pre> | |||
<p>Generates a tagdiff report for all the changes that have been | |||
made in the <code>Apache BCEL</code> module between the tags | |||
<code>initial</code> and <code>BCEL_5_0</code>. It writes these changes | |||
into the file <code>diff.xml</code>.</p> | |||
<pre> | |||
<tagdiff failonerror="true" | |||
baseURL="http://svn.apache.org/repos/asf/jakarta/bcel/" | |||
destfile="diff.xml" | |||
tag1="BCEL_5_0" | |||
tag2="trunk" | |||
/> | |||
</pre> | |||
<p>Generates a tagdiff report for all the changes that have been made | |||
in the <code>Apache BCEL</code> module between the tag | |||
<code>BCEL_5_0</code> and the <code>trunk</code>. It writes these | |||
changes into the file <code>diff.xml</code>.</p> | |||
<pre> | |||
<tagdiff failonerror="true" | |||
baseURL="http://svn.apache.org/repos/asf/jakarta/bcel/" | |||
destfile="diff.xml" | |||
tag1="BCEL_5_0" | |||
/> | |||
</pre> | |||
<p>Does the same, using <code>trunk</code> as <code>tag2</code> | |||
implicitly.</p> | |||
<h4>Generate Report</h4> | |||
<p>This antlib includes a basic XSLT stylesheet that you can use to | |||
generate a HTML report based on the xml output. The following example | |||
illustrates how to generate a HTML report from the XML report.</p> | |||
<pre> | |||
<style in="diff.xml" | |||
out="diff.html" | |||
style="your-path-to/etc/diff.xsl"> | |||
<param name="title" expression="Jakarta BCEL diff"/> | |||
<param name="repo" expression="http://svn.apache.org/repos/asf/jakarta/bcel/trunk"/> | |||
</style> | |||
</pre> | |||
<h4>(Shortened) Example Output</h4> | |||
<pre> | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<tagdiff tag1="BCEL_5_0" svnurl="http://svn.apache.org/repos/asf/jakarta/bcel/" > | |||
<path> | |||
<name><![CDATA[default.properties]]></name> | |||
<action>added</action> | |||
</path> | |||
<path> | |||
<name><![CDATA[xdocs/images/classloader.gif]]></name> | |||
<action>modified</action> | |||
</path> | |||
<path> | |||
<name><![CDATA[README]]></name> | |||
<action>deleted</action> | |||
</path> | |||
</tagdiff> | |||
</pre> | |||
<hr><p align="center">Copyright © 2005 The Apache Software Foundation. All rights | |||
Reserved.</p> | |||
</body> | |||
</html> | |||
@@ -32,7 +32,7 @@ | |||
</xsl:copy> | |||
</xsl:template> | |||
<xsl:template match="revisiondiff"> | |||
<xsl:template match="revisiondiff|tagdiff"> | |||
<HTML> | |||
<HEAD> | |||
<TITLE><xsl:value-of select="$title"/></TITLE> | |||
@@ -60,7 +60,7 @@ | |||
<h1> | |||
<a name="top"><xsl:value-of select="$title"/></a> | |||
</h1> | |||
diff between <xsl:value-of select="@start"/> and <xsl:value-of select="@end"/> | |||
diff between <xsl:value-of select="@start"/><xsl:value-of select="@tag1"/> and <xsl:value-of select="@end"/><xsl:value-of select="@tag2"/> | |||
<p align="right">Designed for use with <a href="http://ant.apache.org/">Apache Ant</a>.</p> | |||
<hr size="2"/> | |||
<a name="TOP"/> |
@@ -46,7 +46,7 @@ | |||
<target name="report" depends="diff-using-url"> | |||
<style in="${tmpdir}/diff.xml" | |||
out="${tmpdir}/diff.html" | |||
style="src/etc/revisiondiff.xsl"> | |||
style="src/etc/diff.xsl"> | |||
<param name="title" expression="Jakarta BCEL diff"/> | |||
<param name="repo" expression="http://svn.apache.org/repos/asf/jakarta/bcel/trunk"/> | |||
</style> | |||
@@ -0,0 +1,63 @@ | |||
<?xml version="1.0"?> | |||
<!-- | |||
Copyright 2005 The Apache Software Foundation | |||
Licensed under the Apache License, Version 2.0 (the "License"); | |||
you may not use this file except in compliance with the License. | |||
You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
--> | |||
<project name="revisiondiff-test" basedir="../../../" | |||
default="diff-with-implicit-trunk" | |||
xmlns:svn="antlib:org.apache.tools.ant.taskdefs.svn"> | |||
<property name="tmpdir" value="tmpdir"/> | |||
<target name="dir-prep"> | |||
<mkdir dir="${tmpdir}"/> | |||
</target> | |||
<target name="diff-with-two-tags" depends="dir-prep"> | |||
<svn:tagdiff failonerror="true" | |||
baseURL="http://svn.apache.org/repos/asf/jakarta/bcel/" | |||
destfile="${tmpdir}/diff.xml" | |||
tag2="BCEL_5_0" tag1="initial"/> | |||
</target> | |||
<target name="diff-with-explicit-trunk" depends="dir-prep"> | |||
<svn:tagdiff failonerror="true" | |||
baseURL="http://svn.apache.org/repos/asf/jakarta/bcel/" | |||
destfile="${tmpdir}/diff.xml" | |||
tag1="BCEL_5_0" tag2="trunk"/> | |||
</target> | |||
<target name="diff-with-implicit-trunk" depends="dir-prep"> | |||
<svn:tagdiff failonerror="true" | |||
baseURL="http://svn.apache.org/repos/asf/jakarta/bcel/" | |||
destfile="${tmpdir}/diff.xml" | |||
tag1="BCEL_5_0"/> | |||
</target> | |||
<!--target name="report" depends="diff-with-implicit-trunk"--> | |||
<target name="report"> | |||
<style in="/tmp/diff.xml" | |||
out="/tmp/diff.html" | |||
style="src/etc/diff.xsl"> | |||
<param name="title" expression="Jakarta BCEL diff"/> | |||
<param name="repo" expression="http://svn.apache.org/repos/asf/jakarta/bcel/trunk"/> | |||
</style> | |||
</target> | |||
<target name="cleanup"> | |||
<delete dir="${tmpdir}" /> | |||
</target> | |||
</project> |
@@ -0,0 +1,196 @@ | |||
/* | |||
* Copyright 2005 The Apache Software Foundation | |||
* | |||
* Licensed under the Apache License, Version 2.0 (the "License"); | |||
* you may not use this file except in compliance with the License. | |||
* You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
* | |||
*/ | |||
package org.apache.tools.ant.taskdefs.svn; | |||
import java.io.BufferedReader; | |||
import java.io.File; | |||
import java.io.FileOutputStream; | |||
import java.io.FileReader; | |||
import java.io.IOException; | |||
import java.io.OutputStreamWriter; | |||
import java.io.PrintWriter; | |||
import java.io.UnsupportedEncodingException; | |||
import java.util.ArrayList; | |||
import java.util.StringTokenizer; | |||
import org.apache.tools.ant.BuildException; | |||
import org.apache.tools.ant.Project; | |||
import org.apache.tools.ant.util.FileUtils; | |||
/** | |||
* Parses the output of a svn diff command and/or writes an XML report | |||
* based on such a diff output. | |||
* | |||
* It produces an XML output representing the list of changes. | |||
*/ | |||
final class SvnDiffHandler { | |||
/** | |||
* Token to identify the word file in the rdiff log | |||
*/ | |||
private static final String INDEX = "Index: "; | |||
/** | |||
* Token to identify a deleted file based on the Index line. | |||
*/ | |||
private static final String DELETED = " (deleted)"; | |||
/** | |||
* Token to identify added files based on the diff line. | |||
*/ | |||
private static final String IS_NEW = "\t(revision 0)"; | |||
/** | |||
* Token that starts diff line of old revision. | |||
*/ | |||
private static final String DASHES = "--- "; | |||
/** | |||
* Parse the tmpFile and return and array of entries to be written | |||
* in the output. | |||
* | |||
* @param tmpFile the File containing the output of the svn rdiff command | |||
* @return the entries in the output | |||
* @exception BuildException if an error occurs | |||
*/ | |||
static SvnEntry.Path[] parseDiff(File tmpFile) throws BuildException { | |||
// parse the output of the command | |||
BufferedReader reader = null; | |||
try { | |||
reader = new BufferedReader(new FileReader(tmpFile)); | |||
ArrayList entries = new ArrayList(); | |||
String line = reader.readLine(); | |||
String name = null; | |||
String currDiffLine = null; | |||
boolean deleted = false; | |||
boolean added = false; | |||
while (null != line) { | |||
if (line.length() > INDEX.length()) { | |||
if (line.startsWith(INDEX)) { | |||
if (name != null) { | |||
SvnEntry.Path p = | |||
new SvnEntry.Path(name, | |||
deleted | |||
? SvnEntry.Path.DELETED | |||
: (added | |||
? SvnEntry.Path.ADDED | |||
: SvnEntry.Path.MODIFIED) | |||
); | |||
entries.add(p); | |||
deleted = added = false; | |||
} | |||
name = line.substring(INDEX.length()); | |||
if (line.endsWith(DELETED)) { | |||
name = name.substring(0, name.length() | |||
- DELETED.length()); | |||
deleted = true; | |||
} | |||
currDiffLine = DASHES + name; | |||
} else if (currDiffLine != null | |||
&& line.startsWith(currDiffLine) | |||
&& line.endsWith(IS_NEW)) { | |||
added = true; | |||
} | |||
} | |||
line = reader.readLine(); | |||
} | |||
if (name != null) { | |||
SvnEntry.Path p = new SvnEntry.Path(name, | |||
deleted | |||
? SvnEntry.Path.DELETED | |||
: (added | |||
? SvnEntry.Path.ADDED | |||
: SvnEntry.Path.MODIFIED) | |||
); | |||
entries.add(p); | |||
} | |||
SvnEntry.Path[] array = (SvnEntry.Path[]) | |||
entries.toArray(new SvnEntry.Path[entries.size()]); | |||
return array; | |||
} catch (IOException e) { | |||
throw new BuildException("Error in parsing", e); | |||
} finally { | |||
FileUtils.close(reader); | |||
} | |||
} | |||
/** | |||
* Write the diff log. | |||
* | |||
* @param entries a <code>SvnRevisionEntry[]</code> value | |||
* @exception BuildException if an error occurs | |||
*/ | |||
static void writeDiff(File destFile, SvnEntry.Path[] entries, | |||
String rootElementName, | |||
String tag1Name, String tag1Value, | |||
String tag2Name, String tag2Value, | |||
String svnURL) throws BuildException { | |||
FileOutputStream output = null; | |||
try { | |||
output = new FileOutputStream(destFile); | |||
PrintWriter writer = new PrintWriter( | |||
new OutputStreamWriter(output, "UTF-8")); | |||
writer.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); | |||
writer.print("<" + rootElementName + " "); | |||
if (tag1Name != null && tag1Value != null) { | |||
writer.print(tag1Name + "=\"" + tag1Value + "\" "); | |||
} | |||
if (tag2Name != null && tag2Value != null) { | |||
writer.print(tag2Name + "=\"" + tag2Value + "\" "); | |||
} | |||
if (svnURL != null) { | |||
writer.print("svnurl=\"" + svnURL + "\" "); | |||
} | |||
writer.println(">"); | |||
for (int i = 0, c = entries.length; i < c; i++) { | |||
writeRevisionEntry(writer, entries[i]); | |||
} | |||
writer.println("</" + rootElementName + ">"); | |||
writer.flush(); | |||
writer.close(); | |||
} catch (UnsupportedEncodingException uee) { | |||
throw new BuildException(uee); | |||
} catch (IOException ioe) { | |||
throw new BuildException(ioe.toString(), ioe); | |||
} finally { | |||
FileUtils.close(output); | |||
} | |||
} | |||
/** | |||
* Write a single entry to the given writer. | |||
* | |||
* @param writer a <code>PrintWriter</code> value | |||
* @param entry a <code>SvnRevisionEntry</code> value | |||
*/ | |||
private static void writeRevisionEntry(PrintWriter writer, | |||
SvnEntry.Path entry) { | |||
writer.println("\t<path>"); | |||
writer.println("\t\t<name><![CDATA[" + entry.getName() + "]]></name>"); | |||
writer.println("\t\t<action>" + entry.getActionDescription() | |||
+ "</action>"); | |||
writer.println("\t</path>"); | |||
} | |||
} |
@@ -39,10 +39,11 @@ import org.apache.tools.ant.util.FileUtils; | |||
* <!-- Root element --> | |||
* <!ELEMENT revisiondiff ( paths? ) > | |||
* <!-- Start revision of the report --> | |||
* <!ATTLIST revisiondiff startRevision NMTOKEN #IMPLIED > | |||
* <!ATTLIST revisiondiff start NMTOKEN #IMPLIED > | |||
* <!-- End revision of the report --> | |||
* <!ATTLIST revisiondiff endRevision NMTOKEN #IMPLIED > | |||
* <!-- Start date of the report --> | |||
* <!ATTLIST revisiondiff end NMTOKEN #IMPLIED > | |||
* <!-- Subversion URL if known --> | |||
* <!ATTLIST revisiondiff svnurl NMTOKEN #IMPLIED > | |||
* | |||
* <!-- Path added, changed or removed --> | |||
* <!ELEMENT path ( name,action ) > | |||
@@ -60,25 +61,6 @@ public class SvnRevisionDiff extends AbstractSvnTask { | |||
*/ | |||
private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); | |||
/** | |||
* Token to identify the word file in the rdiff log | |||
*/ | |||
static final String INDEX = "Index: "; | |||
/** | |||
* Token to identify a deleted file based on the Index line. | |||
*/ | |||
static final String DELETED = " (deleted)"; | |||
/** | |||
* Token to identify added files based on the diff line. | |||
*/ | |||
static final String IS_NEW = "\t(revision 0)"; | |||
/** | |||
* Token that starts diff line of old revision. | |||
*/ | |||
static final String DASHES = "--- "; | |||
/** | |||
* The earliest revision from which diffs are to be included in the report. | |||
*/ | |||
@@ -145,12 +127,13 @@ public class SvnRevisionDiff extends AbstractSvnTask { | |||
// run the svn command | |||
super.execute(); | |||
// parse the rdiff | |||
SvnEntry.Path[] entries = parseDiff(tmpFile); | |||
// parse the diff | |||
SvnEntry.Path[] entries = SvnDiffHandler.parseDiff(tmpFile); | |||
// write the revision diff | |||
writeRevisionDiff(entries); | |||
SvnDiffHandler.writeDiff(mydestfile, entries, "revisiondiff", | |||
"start", mystartRevision, | |||
"end", myendRevision, getSvnURL()); | |||
} finally { | |||
if (tmpFile != null) { | |||
tmpFile.delete(); | |||
@@ -158,148 +141,6 @@ public class SvnRevisionDiff extends AbstractSvnTask { | |||
} | |||
} | |||
/** | |||
* Parse the tmpFile and return and array of SvnRevisionEntry to be | |||
* written in the output. | |||
* | |||
* @param tmpFile the File containing the output of the svn rdiff command | |||
* @return the entries in the output | |||
* @exception BuildException if an error occurs | |||
*/ | |||
private SvnEntry.Path[] parseDiff(File tmpFile) throws BuildException { | |||
// parse the output of the command | |||
BufferedReader reader = null; | |||
try { | |||
reader = new BufferedReader(new FileReader(tmpFile)); | |||
ArrayList entries = new ArrayList(); | |||
String line = reader.readLine(); | |||
String name = null; | |||
String currDiffLine = null; | |||
boolean deleted = false; | |||
boolean added = false; | |||
while (null != line) { | |||
if (line.length() > INDEX.length()) { | |||
if (line.startsWith(INDEX)) { | |||
if (name != null) { | |||
SvnEntry.Path p = | |||
new SvnEntry.Path(name, | |||
deleted | |||
? SvnEntry.Path.DELETED | |||
: (added | |||
? SvnEntry.Path.ADDED | |||
: SvnEntry.Path.MODIFIED) | |||
); | |||
entries.add(p); | |||
deleted = added = false; | |||
} | |||
name = line.substring(INDEX.length()); | |||
if (line.endsWith(DELETED)) { | |||
name = name.substring(0, name.length() | |||
- DELETED.length()); | |||
deleted = true; | |||
} | |||
currDiffLine = DASHES + name; | |||
} else if (currDiffLine != null | |||
&& line.startsWith(currDiffLine) | |||
&& line.endsWith(IS_NEW)) { | |||
added = true; | |||
} | |||
} | |||
line = reader.readLine(); | |||
} | |||
if (name != null) { | |||
SvnEntry.Path p = new SvnEntry.Path(name, | |||
deleted | |||
? SvnEntry.Path.DELETED | |||
: (added | |||
? SvnEntry.Path.ADDED | |||
: SvnEntry.Path.MODIFIED) | |||
); | |||
entries.add(p); | |||
} | |||
SvnEntry.Path[] array = (SvnEntry.Path[]) | |||
entries.toArray(new SvnEntry.Path[entries.size()]); | |||
return array; | |||
} catch (IOException e) { | |||
throw new BuildException("Error in parsing", e); | |||
} finally { | |||
if (reader != null) { | |||
try { | |||
reader.close(); | |||
} catch (IOException e) { | |||
log(e.toString(), Project.MSG_ERR); | |||
} | |||
} | |||
} | |||
} | |||
/** | |||
* Write the rdiff log. | |||
* | |||
* @param entries a <code>SvnRevisionEntry[]</code> value | |||
* @exception BuildException if an error occurs | |||
*/ | |||
private void writeRevisionDiff(SvnEntry.Path[] entries) throws BuildException { | |||
FileOutputStream output = null; | |||
try { | |||
output = new FileOutputStream(mydestfile); | |||
PrintWriter writer = new PrintWriter( | |||
new OutputStreamWriter(output, "UTF-8")); | |||
writer.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); | |||
writer.print("<revisiondiff "); | |||
if (mystartRevision != null) { | |||
writer.print("start=\"" + mystartRevision + "\" "); | |||
} | |||
if (myendRevision != null) { | |||
writer.print("end=\"" + myendRevision + "\" "); | |||
} | |||
if (getSvnURL() != null) { | |||
writer.print("svnurl=\"" + getSvnURL() + "\" "); | |||
} | |||
writer.println(">"); | |||
for (int i = 0, c = entries.length; i < c; i++) { | |||
writeRevisionEntry(writer, entries[i]); | |||
} | |||
writer.println("</revisiondiff>"); | |||
writer.flush(); | |||
writer.close(); | |||
} catch (UnsupportedEncodingException uee) { | |||
log(uee.toString(), Project.MSG_ERR); | |||
} catch (IOException ioe) { | |||
throw new BuildException(ioe.toString(), ioe); | |||
} finally { | |||
if (null != output) { | |||
try { | |||
output.close(); | |||
} catch (IOException ioe) { | |||
log(ioe.toString(), Project.MSG_ERR); | |||
} | |||
} | |||
} | |||
} | |||
/** | |||
* Write a single entry to the given writer. | |||
* | |||
* @param writer a <code>PrintWriter</code> value | |||
* @param entry a <code>SvnRevisionEntry</code> value | |||
*/ | |||
private void writeRevisionEntry(PrintWriter writer, SvnEntry.Path entry) { | |||
writer.println("\t<path>"); | |||
writer.println("\t\t<name><![CDATA[" + entry.getName() + "]]></name>"); | |||
writer.println("\t\t<action>" + entry.getActionDescription() | |||
+ "</action>"); | |||
writer.println("\t</path>"); | |||
} | |||
/** | |||
* Validate the parameters specified for task. | |||
* | |||
@@ -0,0 +1,210 @@ | |||
/* | |||
* Copyright 2005 The Apache Software Foundation | |||
* | |||
* Licensed under the Apache License, Version 2.0 (the "License"); | |||
* you may not use this file except in compliance with the License. | |||
* You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
* | |||
*/ | |||
package org.apache.tools.ant.taskdefs.svn; | |||
import java.io.BufferedReader; | |||
import java.io.File; | |||
import java.io.FileOutputStream; | |||
import java.io.FileReader; | |||
import java.io.IOException; | |||
import java.io.OutputStreamWriter; | |||
import java.io.PrintWriter; | |||
import java.io.UnsupportedEncodingException; | |||
import java.util.ArrayList; | |||
import java.util.StringTokenizer; | |||
import org.apache.tools.ant.BuildException; | |||
import org.apache.tools.ant.Project; | |||
import org.apache.tools.ant.util.FileUtils; | |||
/** | |||
* Examines the output of svn diff between two tags or a tag and trunk. | |||
* | |||
* <p>This task only works if you follow the best-practice structure of | |||
* <pre> | |||
* BASEURL | |||
* | | |||
* | | |||
* -----> trunk | |||
* -----> tags | |||
* | | |||
* | | |||
* ----------> tag1 | |||
* ----------> tag2 | |||
* </pre> | |||
* | |||
* It produces an XML output representing the list of changes. | |||
* <PRE> | |||
* <!-- Root element --> | |||
* <!ELEMENT tagdiff ( paths? ) > | |||
* <!-- First tag --> | |||
* <!ATTLIST tagdiff tag1 NMTOKEN #IMPLIED > | |||
* <!-- Second tag --> | |||
* <!ATTLIST tagdiff tag2 NMTOKEN #IMPLIED > | |||
* <!-- Subversion BaseURL --> | |||
* <!ATTLIST tagdiff svnurl NMTOKEN #IMPLIED > | |||
* | |||
* <!-- Path added, changed or removed --> | |||
* <!ELEMENT path ( name,action ) > | |||
* <!-- Name of the file --> | |||
* <!ELEMENT name ( #PCDATA ) > | |||
* <!ELEMENT action (added|modified|deleted)> | |||
* </PRE> | |||
* | |||
* @ant.task name="svntagdiff" | |||
*/ | |||
public class SvnTagDiff extends AbstractSvnTask { | |||
/** | |||
* Used to create the temp file for svn log | |||
*/ | |||
private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); | |||
/** | |||
* The earliest revision from which diffs are to be included in the report. | |||
*/ | |||
private String tag1; | |||
/** | |||
* The latest revision from which diffs are to be included in the report. | |||
*/ | |||
private String tag2; | |||
/** | |||
* The file in which to write the diff report. | |||
*/ | |||
private File mydestfile; | |||
/** | |||
* Base URL. | |||
*/ | |||
private String baseURL; | |||
/** | |||
* Set the first tag. | |||
* | |||
* @param s the first tag. | |||
*/ | |||
public void setTag1(String s) { | |||
tag1 = s; | |||
} | |||
/** | |||
* Set the second tag. | |||
* | |||
* @param s the second tag. | |||
*/ | |||
public void setTag2(String s) { | |||
tag2 = s; | |||
} | |||
/** | |||
* Set the output file for the diff. | |||
* | |||
* @param f the output file for the diff. | |||
*/ | |||
public void setDestFile(File f) { | |||
mydestfile = f; | |||
} | |||
/** | |||
* Set the base URL from which to calculate tag URLs. | |||
* | |||
* @param u the base URL from which to calculate tag URLs. | |||
*/ | |||
public void setBaseURL(String u) { | |||
baseURL = u; | |||
if (!u.endsWith("/")) { | |||
baseURL += "/"; | |||
} | |||
} | |||
/** | |||
* Execute task. | |||
* | |||
* @exception BuildException if an error occurs | |||
*/ | |||
public void execute() throws BuildException { | |||
// validate the input parameters | |||
validate(); | |||
// build the rdiff command | |||
setSubCommand("diff"); | |||
addSubCommandArgument("--no-diff-deleted"); | |||
if (tag1.equals("trunk") || tag1.equals("trunk/")) { | |||
addSubCommandArgument(baseURL + "trunk/"); | |||
} else { | |||
if (tag1.endsWith("/")) { | |||
addSubCommandArgument(baseURL + "tags/" + tag1); | |||
} else { | |||
addSubCommandArgument(baseURL + "tags/" + tag1 + "/"); | |||
} | |||
} | |||
if (tag2 == null || tag2.equals("trunk") || tag2.equals("trunk/")) { | |||
addSubCommandArgument(baseURL + "trunk/"); | |||
} else { | |||
if (tag2.endsWith("/")) { | |||
addSubCommandArgument(baseURL + "tags/" + tag2); | |||
} else { | |||
addSubCommandArgument(baseURL + "tags/" + tag2 + "/"); | |||
} | |||
} | |||
File tmpFile = null; | |||
try { | |||
tmpFile = | |||
FILE_UTILS.createTempFile("svntagdiff", ".log", null); | |||
tmpFile.deleteOnExit(); | |||
setOutput(tmpFile); | |||
// run the svn command | |||
super.execute(); | |||
// parse the diff | |||
SvnEntry.Path[] entries = SvnDiffHandler.parseDiff(tmpFile); | |||
// write the revision diff | |||
SvnDiffHandler.writeDiff(mydestfile, entries, "tagdiff", | |||
"tag1", tag1, "tag2", | |||
tag2 == null ? "trunk" : tag2, | |||
baseURL); | |||
} finally { | |||
if (tmpFile != null) { | |||
tmpFile.delete(); | |||
} | |||
} | |||
} | |||
/** | |||
* Validate the parameters specified for task. | |||
* | |||
* @exception BuildException if a parameter is not correctly set | |||
*/ | |||
private void validate() throws BuildException { | |||
if (null == mydestfile) { | |||
throw new BuildException("Destfile must be set."); | |||
} | |||
if (null == tag1) { | |||
throw new BuildException("tag1 must be set."); | |||
} | |||
if (null == baseURL) { | |||
throw new BuildException("baseURL must be set."); | |||
} | |||
} | |||
} |
@@ -27,4 +27,8 @@ | |||
name="revisiondiff" | |||
classname="org.apache.tools.ant.taskdefs.svn.SvnRevisionDiff" | |||
/> | |||
<taskdef | |||
name="tagdiff" | |||
classname="org.apache.tools.ant.taskdefs.svn.SvnTagDiff" | |||
/> | |||
</antlib> |
@@ -74,9 +74,9 @@ public class SvnRevisionDiffTest extends BuildFileTest { | |||
int end = log.indexOf(">", start); | |||
Assert.assertTrue(end > -1); | |||
Assert.assertTrue(log.indexOf("start=\"152904\"", start) > -1); | |||
Assert.assertTrue(log.indexOf("start=\"152904\"") < end); | |||
Assert.assertTrue(log.indexOf("start=\"152904\"", start) < end); | |||
Assert.assertTrue(log.indexOf("end=\"153682\"", start) > -1); | |||
Assert.assertTrue(log.indexOf("end=\"153682\"") < end); | |||
Assert.assertTrue(log.indexOf("end=\"153682\"", start) < end); | |||
} | |||
private static final void assertAttributesNoURL(String log) { | |||
@@ -0,0 +1,144 @@ | |||
/* | |||
* Copyright 2005 The Apache Software Foundation | |||
* | |||
* Licensed under the Apache License, Version 2.0 (the "License"); | |||
* you may not use this file except in compliance with the License. | |||
* You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
* | |||
*/ | |||
package org.apache.tools.ant.taskdefs.svn; | |||
import java.io.IOException; | |||
import java.io.FileReader; | |||
import org.apache.tools.ant.BuildFileTest; | |||
import org.apache.tools.ant.util.FileUtils; | |||
import junit.framework.Assert; | |||
/** | |||
*/ | |||
public class SvnTagDiffTest extends BuildFileTest { | |||
public SvnTagDiffTest(String name) { | |||
super(name); | |||
} | |||
public void setUp() { | |||
configureProject("src/etc/testcases/tagdiff.xml"); | |||
} | |||
public void tearDown() { | |||
executeTarget("cleanup"); | |||
} | |||
public void testDiffWithTwoTags() throws IOException { | |||
String log = executeTargetAndReadLogFully("diff-with-two-tags"); | |||
assertAttributes(log, "initial", "BCEL_5_0"); | |||
assertAdded1(log); | |||
} | |||
public void testDiffWithExplicitTrunk() throws IOException { | |||
String log = executeTargetAndReadLogFully("diff-with-explicit-trunk"); | |||
assertDiffWithTrunk(log); | |||
} | |||
public void testDiffWithImplicitTrunk() throws IOException { | |||
String log = executeTargetAndReadLogFully("diff-with-implicit-trunk"); | |||
assertDiffWithTrunk(log); | |||
} | |||
private static void assertDiffWithTrunk(String log) { | |||
assertAttributes(log, "BCEL_5_0", "trunk"); | |||
assertAdded(log); | |||
assertModified(log); | |||
assertDeleted(log); | |||
} | |||
private String executeTargetAndReadLogFully(String target) | |||
throws IOException { | |||
executeTarget(target); | |||
FileReader r = new FileReader(getProject() | |||
.resolveFile("tmpdir/diff.xml")); | |||
try { | |||
return FileUtils.readFully(r); | |||
} finally { | |||
r.close(); | |||
} | |||
} | |||
private static final void assertAttributes(String log, String tag1, | |||
String tag2) { | |||
int start = log.indexOf("<tagdiff"); | |||
Assert.assertTrue(start > -1); | |||
int end = log.indexOf(">", start); | |||
Assert.assertTrue(end > -1); | |||
Assert.assertTrue(log.indexOf("tag1=\"" + tag1 + "\"", start) > -1); | |||
Assert.assertTrue(log.indexOf("tag1=\"" + tag1 + "\"", start) < end); | |||
Assert.assertTrue(log.indexOf("tag2=\"" + tag2 + "\"", start) > -1); | |||
Assert.assertTrue(log.indexOf("tag2=\"" + tag2 + "\"", start) < end); | |||
Assert.assertTrue(log.indexOf("svnurl=\"http://svn.apache.org/repos/" | |||
+ "asf/jakarta/bcel/\"", start) > -1); | |||
Assert.assertTrue(log.indexOf("svnurl=\"http://svn.apache.org/repos/" | |||
+ "asf/jakarta/bcel/\"", start) < end); | |||
} | |||
private static final void assertAdded(String log) { | |||
int name = log.indexOf("<![CDATA[LICENSE.txt]]>"); | |||
Assert.assertTrue(name > -1); | |||
int pathAfterName = log.indexOf("</path>", name); | |||
Assert.assertTrue(pathAfterName > -1); | |||
Assert.assertTrue(log.indexOf("<action>added</action>", name) > -1); | |||
Assert.assertTrue(log.indexOf("<action>added</action>", name) | |||
< pathAfterName); | |||
} | |||
private static final void assertModified(String log) { | |||
int name = log.indexOf("<name><![CDATA[src/java/org/apache/bcel/" | |||
+ "Repository.java]]></name>"); | |||
Assert.assertTrue(name > -1); | |||
int pathAfterName = log.indexOf("</path>", name); | |||
Assert.assertTrue(pathAfterName > -1); | |||
Assert.assertTrue(log.indexOf("<action>modified</action>", name) > -1); | |||
Assert.assertTrue(log.indexOf("<action>modified</action>", name) | |||
< pathAfterName); | |||
} | |||
private static final void assertDeleted(String log) { | |||
int name = log.indexOf("<name><![CDATA[LICENSE]]></name>"); | |||
Assert.assertTrue(name > -1); | |||
int pathAfterName = log.indexOf("</path>", name); | |||
Assert.assertTrue(pathAfterName > -1); | |||
Assert.assertTrue(log.indexOf("<action>deleted</action>", name) > -1); | |||
Assert.assertTrue(log.indexOf("<action>deleted</action>", name) | |||
< pathAfterName); | |||
} | |||
private static final void assertAdded1(String log) { | |||
int name = log.indexOf("<name><![CDATA[src/java/org/apache/bcel/" | |||
+ "Repository.java]]></name>"); | |||
Assert.assertTrue(name > -1); | |||
int pathAfterName = log.indexOf("</path>", name); | |||
Assert.assertTrue(pathAfterName > -1); | |||
Assert.assertTrue(log.indexOf("<action>added</action>", name) > -1); | |||
Assert.assertTrue(log.indexOf("<action>added</action>", name) | |||
< pathAfterName); | |||
} | |||
} |