diff --git a/build.xml b/build.xml index 3d1d8ceb9..c2aea9068 100644 --- a/build.xml +++ b/build.xml @@ -790,6 +790,7 @@ + diff --git a/docs/manual/CoreTasks/cvstagdiff.html b/docs/manual/CoreTasks/cvstagdiff.html new file mode 100644 index 000000000..795b776e6 --- /dev/null +++ b/docs/manual/CoreTasks/cvstagdiff.html @@ -0,0 +1,159 @@ + + + + +CvsTagDiff Task + + + + +

CvsTagDiff

+

Description

+

Generates an XML-formatted report file of the changes between two tags or dates recorded in a +CVS repository.

+

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributeDescriptionRequired
startTagThe earliest tag from which diffs are to be + included in the report.exactly one of the two.
startDateThe earliest date from which diffs are to be + included in the report.
endTagThe latest tag from which diffs are to be + included in the report.exactly one of the two.
endDateThe latest date from which diffs are to be + included in the report.
destfileThe file in which to write the diff report.Yes
+ +

Parameters inherited from the cvs task

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributeDescriptionRequired
compressiontrue, false, or the number 1-9 (corresponding to possible values for CVS -z# argument). Any other value is treated as falseNo. Defaults to no compression. if passed true, level 3 compression is assumed.
cvsRootthe CVSROOT variable.No
cvsRshthe CVS_RSH variable.No
packagethe package/module to analyze.Yes
quietsuppress informational messages.No, default "false"
portPort used by CVS to communicate with the server.No, default port 2401.
passfilePassword file to read passwords from.No, default file ~/.cvspass.
failonerrorStop the buildprocess if the command exits with a + returncode other than 0. Defaults to falseNo
+ +

Examples

+
  <cvstagdiff cvsRoot=":pserver:anoncvs@cvs.apache.org:/home/cvspublic"
+                destfile="tagdiff.xml"
+                package="jakarta-ant"
+                startTag="ANT_14"
+                endTag="ANT_141"
+  />
+ +

Generates a tagdiff report for all the changes that have been made +in the jakarta-ant module between the tags ANT_14 and ANT_141. +It writes these changes into the file tagdiff.xml.

+ +
  <cvstagdiff
+                destfile="tagdiff.xml"
+                package="jakarta-ant"
+                startDate="2002-01-01"
+                endDate="2002-31-01"
+  />
+ +

Generates a tagdiff report for all the changes that have been made +in the jakarta-ant module in january 2002. In this example cvsRoot +has not been set. The current cvsRoot will be used (assuming the build is started +from a folder stored in cvs. +It writes these changes into the file tagdiff.xml.

+ +

Generate Report

+

Ant 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.

+ +
+        <style in="tagdiff.xml" 
+               out="tagdiff.html" 
+               style="${ant.home}/etc/tagdiff.xsl">
+          <param name="title" expression="Ant Diff"/>
+          <param name="module" expression="jakarta-ant"/>
+          <param name="cvsweb" expression="http://cvs.apache.org/viewcvs/"/>
+        </style>
+
+ +

Sample Output

+
+<?xml version="1.0" encoding="UTF-8"?>
+<tagdiff startTag="ANT_14" endTag="ANT_141">
+  <entry>
+    <file>
+      <name>src/main/org/apache/tools/ant/DirectoryScanner.java</name>
+      <revision>1.15.2.1</revision>
+      <prevrevision>1.15</prevrevision>
+    </file>
+  </entry>
+</tagdiff>
+
+ +

Copyright © 2002 Apache Software Foundation. All rights +Reserved.

+ + + + diff --git a/docs/manual/coretasklist.html b/docs/manual/coretasklist.html index a309f92b0..fa7a63f38 100644 --- a/docs/manual/coretasklist.html +++ b/docs/manual/coretasklist.html @@ -33,6 +33,7 @@ Cvs
CvsChangeLog
CVSPass
+CvsTagDiff
Delete
Deltree
Dependset
diff --git a/docs/manual/tasksoverview.html b/docs/manual/tasksoverview.html index 59837af98..0ee562b7f 100644 --- a/docs/manual/tasksoverview.html +++ b/docs/manual/tasksoverview.html @@ -959,6 +959,13 @@ documentation.

has the same affect as a cvs login command.

+ + CvsTagDiff +

Generates an XML-formatted report file of the changes between + two tags or dates recorded in a CVS repository.

+ + ClearCase

Tasks to perform the ClearCase cccheckin, cccheckout, diff --git a/src/etc/tagdiff.xsl b/src/etc/tagdiff.xsl new file mode 100644 index 000000000..4dac8f4b7 --- /dev/null +++ b/src/etc/tagdiff.xsl @@ -0,0 +1,162 @@ + + + + + + + + + + + + + + + + + + + + + <xsl:value-of select="$title"/> + + + +

+ +

+ Tagdiff between and + +

Designed for use with Ant.

+
+ + + + + +
+ New Files | + Modified Files | + Removed Files +
+ + + New Files + New + + + + + Modified Files + Modified + + + + + Removed Files + Removed + + +
+ + + + + + + + + + + +
+ + - entries + + (back to top) + + + + + + + +
    + +
+ + + + + + + + + + + + + + + + + + + + mailto: + + + + + + +
  • + + / + + + + + + + + /?rev=&content-type=text/x-cvsweb-markup + + + /?r1=&r2=&diff_format=h + + () + + +
  • +
    + + + + + + + diff --git a/src/main/org/apache/tools/ant/taskdefs/cvslib/CvsTagDiff.java b/src/main/org/apache/tools/ant/taskdefs/cvslib/CvsTagDiff.java new file mode 100644 index 000000000..a8c482d0e --- /dev/null +++ b/src/main/org/apache/tools/ant/taskdefs/cvslib/CvsTagDiff.java @@ -0,0 +1,535 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2002 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Ant", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + */ +package org.apache.tools.ant.taskdefs.cvslib; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.Task; +import org.apache.tools.ant.taskdefs.Cvs; +import org.apache.tools.ant.util.FileUtils; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.util.Enumeration; +import java.util.Vector; + +/** + * Cvs tag diff. + * The task will examine the output of cvs rdiff between two tags. + * It produces an XML output representing the list of changes. + *
    + * <!-- Root element -->
    + * <!ELEMENT tagdiff ( entry+ ) >
    + * <!-- Start tag of the report -->
    + * <!ATTLIST tagdiff startTag NMTOKEN #IMPLIED >
    + * <!-- End tag of the report -->
    + * <!ATTLIST tagdiff endTag NMTOKEN #IMPLIED >
    + * <!-- Start date of the report -->
    + * <!ATTLIST tagdiff startDate NMTOKEN #IMPLIED >
    + * <!-- End date of the report -->
    + * <!ATTLIST tagdiff endDate NMTOKEN #IMPLIED >
    + *
    + * <!-- CVS tag entry -->
    + * <!ELEMENT entry ( file ) >
    + * <!-- File added, changed or removed -->
    + * <!ELEMENT file ( name, revision?, prevrevision? ) >
    + * <!-- Name of the file -->
    + * <!ELEMENT name ( #PCDATA ) >
    + * <!-- Revision number -->
    + * <!ELEMENT revision ( #PCDATA ) >
    + * <!-- Previous revision number -->
    + * <!ELEMENT prevrevision ( #PCDATA ) >
    + * 
    + * + * @author Frederic Lavigne + * @version $Revision$ $Date$ + * @ant.task name="cvstagdiff" + */ +public class CvsTagDiff extends Task { + + /** + * Token to identify a new file in the rdiff log + */ + static final String FILE_IS_NEW = " is new; current revision "; + + /** + * Token to identify a modified file in the rdiff log + */ + static final String FILE_HAS_CHANGED = " changed from revision "; + + /** + * Token to identify a removed file in the rdiff log + */ + static final String FILE_WAS_REMOVED = " is removed"; + + /** + * The cvs task which will perform the rdiff. + */ + private Cvs m_cvs; + + /** + * The cvs package/module to analyse + */ + private String m_package; + + /** + * The earliest tag from which diffs are to be included in the report. + */ + private String m_startTag; + + /** + * The latest tag from which diffs are to be included in the report. + */ + private String m_endTag; + + /** + * The earliest date from which diffs are to be included in the report. + */ + private String m_startDate; + + /** + * The latest date from which diffs are to be included in the report. + */ + private String m_endDate; + + /** + * The file in which to write the diff report. + */ + private File m_destfile; + + /** + * Used to create the temp file for cvs log + */ + private FileUtils m_fileUtils = FileUtils.newFileUtils(); + + /** + * Initialize this task. + * CvsTagDiff initializes a member cvs task in init() to perform the rdiff in execute(). + * + * @exception BuildException if an error occurs + */ + public void init() throws BuildException { + m_cvs = (Cvs)getProject().createTask("cvs"); + } + + /** + * @see org.apache.tools.ant.taskdefs.AbstractCvsTask#setCompressionLevel(int) + */ + public void setCompressionLevel(int level) { + m_cvs.setCompressionLevel(level); + } + + /** + * @see org.apache.tools.ant.taskdefs.AbstractCvsTask#setCompression(boolean) + */ + public void setCompression(boolean usecomp) { + m_cvs.setCompression(usecomp); + } + + /** + * @see org.apache.tools.ant.taskdefs.AbstractCvsTask#setCvsRoot + */ + public void setCvsRoot(String cvsRoot) { + m_cvs.setCvsRoot(cvsRoot); + } + + /** + * @see org.apache.tools.ant.taskdefs.AbstractCvsTask#setCvsRsh + */ + public void setCvsRsh(String rsh) { + m_cvs.setCvsRsh(rsh); + } + + /** + * @see org.apache.tools.ant.taskdefs.AbstractCvsTask#setPackage + */ + public void setPackage(String p) { + m_package = p; + } + + /** + * @see org.apache.tools.ant.taskdefs.AbstractCvsTask#setQuiet + */ + public void setQuiet(boolean quiet) { + m_cvs.setQuiet(quiet); + } + + /** + * @see org.apache.tools.ant.taskdefs.AbstractCvsTask#setPort + */ + public void setPort(int port) { + m_cvs.setPort(port); + } + + /** + * @see org.apache.tools.ant.taskdefs.AbstractCvsTask#setPassfile + */ + public void setPassfile(File f) { + m_cvs.setPassfile(f); + } + + /** + * @see org.apache.tools.ant.taskdefs.AbstractCvsTask#setFailOnError + */ + public void setFailOnError(boolean b) { + m_cvs.setFailOnError(b); + } + + /** + * Set the start tag. + * + * @param s the start tag. + */ + public void setStartTag(String s) { + m_startTag = s; + } + + /** + * Set the start date. + * + * @param s the start date. + */ + public void setStartDate(String s) { + m_startDate = s; + } + + /** + * Set the end tag. + * + * @param s the end tag. + */ + public void setEndTag(String s) { + m_endTag = s; + } + + /** + * Set the end date. + * + * @param s the end date. + */ + public void setEndDate(String s) { + m_endDate = s; + } + + /** + * Set the output file for the diff. + * + * @param f the output file for the diff. + */ + public void setDestFile(File f) { + m_destfile = f; + } + + /** + * Execute task. + * + * @exception BuildException if an error occurs + */ + public void execute() throws BuildException { + // validate the input parameters + validate(); + + // build the rdiff command + String rdiff = "rdiff -s " + + (m_startTag!=null?("-r " + m_startTag):("-D " + m_startDate)) + " " + + (m_endTag!=null?("-r " + m_endTag):("-D " + m_endDate)) + " " + + m_package; + log("Cvs command is " + rdiff, Project.MSG_VERBOSE); + m_cvs.setCommand(rdiff); + + File tmpFile = null; + try { + tmpFile = m_fileUtils.createTempFile("cvstagdiff", ".log", null); + m_cvs.setOutput(tmpFile); + + // run the cvs command + m_cvs.execute(); + + // parse the rdiff + CvsTagEntry[] entries = parseRDiff(tmpFile); + + // write the tag diff + writeTagDiff(entries); + + } finally { + if (tmpFile != null) { + tmpFile.delete(); + } + } + } + + /** + * Parse the tmpFile and return and array of CvsTagEntry to be written in the output. + * + * @param tmpFile the File containing the output of the cvs rdiff command + * @return the entries in the output + * @exception BuildException if an error occurs + */ + private CvsTagEntry[] parseRDiff(File tmpFile) throws BuildException { + // parse the output of the command + BufferedReader reader = null; + + try { + reader = new BufferedReader(new FileReader(tmpFile)); + + // entries are of the form: + // File module/filename is new; current revision 1.1 + // or + // File module/filename changed from revision 1.4 to 1.6 + // or + // File module/filename is removed; not included in release tag SKINLF_12 + int headerLength = 5 + m_package.length() + 1; // get rid of 'File module/" + Vector entries = new Vector(); + + String line = reader.readLine(); + int index; + CvsTagEntry entry = null; + + while (null != line) { + line = line.substring(headerLength); + + if ((index = line.indexOf(FILE_IS_NEW)) != -1) { + // it is a new file + // set the revision but not the prevrevision + String filename = line.substring(0, index); + String rev = line.substring(index + FILE_IS_NEW.length()); + + entries.add(entry = new CvsTagEntry(filename, rev)); + log(entry.toString(), Project.MSG_VERBOSE); + } else if ((index = line.indexOf(FILE_HAS_CHANGED)) != -1) { + // it is a modified file + // set the revision and the prevrevision + String filename = line.substring(0, index); + int revSeparator = line.indexOf(" to ", index); + String prevRevision = line.substring(index + FILE_HAS_CHANGED.length(), revSeparator); + String revision = line.substring(revSeparator + 4); // 4 is " to " length + + entries.add(entry = new CvsTagEntry(filename, revision, prevRevision)); + log(entry.toString(), Project.MSG_VERBOSE); + } else if ((index = line.indexOf(FILE_WAS_REMOVED)) != -1) { + // it is a removed file + String filename = line.substring(0, index); + + entries.add(entry = new CvsTagEntry(filename)); + log(entry.toString(), Project.MSG_VERBOSE); + } + line = reader.readLine(); + } + + CvsTagEntry[] array = new CvsTagEntry[entries.size()]; + entries.copyInto(array); + + return array; + } catch (IOException e) { + throw new BuildException("Error in parsing", e); + } finally { + if (reader != null) { + try { + reader.close(); + } catch (IOException e) { + } + } + } + } + + /** + * Write the rdiff log. + * + * @param entries a CvsTagEntry[] value + * @exception BuildException if an error occurs + */ + private void writeTagDiff(CvsTagEntry[] entries) throws BuildException { + FileOutputStream output = null; + try { + output = new FileOutputStream(m_destfile); + PrintWriter writer = new PrintWriter(new OutputStreamWriter(output, "UTF-8")); + writer.println(""); + writer.print(""); + for (int i = 0, c = entries.length; i < c; i++) { + writeTagEntry(writer, entries[i]); + } + writer.println(""); + 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) { } + } + } + } + + /** + * Write a single entry to the given writer. + * + * @param writer a PrintWriter value + * @param entry a CvsTagEntry value + */ + private void writeTagEntry(PrintWriter writer, CvsTagEntry entry) { + writer.println("\t"); + writer.println("\t\t"); + writer.println("\t\t\t" + entry.getFile() + ""); + if (entry.getRevision() != null) { + writer.println("\t\t\t" + entry.getRevision() + ""); + } + if (entry.getPreviousRevision() != null) { + writer.println("\t\t\t" + entry.getPreviousRevision() + ""); + } + writer.println("\t\t"); + writer.println("\t"); + } + + /** + * Validate the parameters specified for task. + * + * @exception BuildException if a parameter is not correctly set + */ + private void validate() throws BuildException { + if (null == m_package) { + throw new BuildException("Package/module must be set."); + } + + if (null == m_destfile) { + throw new BuildException("Destfile must be set."); + } + + if (null == m_startTag && null == m_startDate) { + throw new BuildException("Start tag or start date must be set."); + } + + if (null != m_startTag && null != m_startDate) { + throw new BuildException("Only one of start tag and start date must be set."); + } + + if (null == m_endTag && null == m_endDate) { + throw new BuildException("End tag or end date must be set."); + } + + if (null != m_endTag && null != m_endDate) { + throw new BuildException("Only one of end tag and end date must be set."); + } + } + + /** + * Holds the information of a line of rdiff + */ + static class CvsTagEntry { + String m_filename; + String m_prevRevision; + String m_revision; + + public CvsTagEntry(String filename) { + this(filename, null, null); + } + + public CvsTagEntry(String filename, String revision) { + this(filename, revision, null); + } + + public CvsTagEntry(String filename, String revision, String prevRevision) { + m_filename = filename; + m_revision = revision; + m_prevRevision = prevRevision; + } + + public String getFile() { + return m_filename; + } + + public String getRevision() { + return m_revision; + } + + public String getPreviousRevision() { + return m_prevRevision; + } + + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append(m_filename); + if ((m_revision == null) && (m_prevRevision == null)) { + buffer.append(" was removed"); + } else if (m_revision != null && m_prevRevision == null) { + buffer.append(" is new; current revision is ").append(m_revision); + } else if (m_revision != null && m_prevRevision != null) { + buffer.append(" has changed from ").append(m_prevRevision).append(" to ").append(m_revision); + } + return buffer.toString(); + } + } + +}