git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@277653 13f79535-47bb-0310-9956-ffa450edef68master
@@ -18,9 +18,3 @@ SVN, matching what the traditional Ant task(s) vor CVS could do. | |||
If you need more than what this libary provides, we encourage you to | |||
check out the existing alternatives. | |||
=============== | |||
The first cut will mimic the implementation of the <cvs> task, it will | |||
even be split into an abstract task and a very thin real task - it may | |||
be possible to base tasks similar to the optional CVS tasks on the | |||
abstract task as well. |
@@ -0,0 +1,61 @@ | |||
<?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="changelog-test" basedir="../../../" | |||
default="log" xmlns:svn="antlib:org.apache.tools.ant.taskdefs.svn"> | |||
<property name="tmpdir" value="tmpdir"/> | |||
<property name="tpfdir" value="${tmpdir}/tpf"/> | |||
<property name="file" value="ebcdic.h"/> | |||
<target name="setup"> | |||
<mkdir dir="${tmpdir}"/> | |||
<svn:svn | |||
svnURL="http://svn.apache.org/repos/asf/httpd/httpd/trunk/os/tpf/" | |||
dest="${tmpdir}"/> | |||
</target> | |||
<target name="log" depends="setup"> | |||
<svn:changelog failonerror="true" dest="${tpfdir}" | |||
destfile="${tmpdir}/log.xml"/> | |||
</target> | |||
<target name="start" depends="setup"> | |||
<svn:changelog failonerror="true" dest="${tpfdir}" | |||
destfile="${tmpdir}/log.xml" start="151000"/> | |||
</target> | |||
<target name="startDate" depends="setup"> | |||
<svn:changelog failonerror="true" dest="${tpfdir}" | |||
destfile="${tmpdir}/log.xml" start="{2004-12-24}"/> | |||
</target> | |||
<target name="end" depends="setup"> | |||
<svn:changelog failonerror="true" dest="${tpfdir}" | |||
destfile="${tmpdir}/log.xml" end="151000"/> | |||
</target> | |||
<target name="endDate" depends="setup"> | |||
<svn:changelog failonerror="true" dest="${tpfdir}" | |||
destfile="${tmpdir}/log.xml" end="{2004-12-24}"/> | |||
</target> | |||
<target name="cleanup"> | |||
<delete dir="${tmpdir}" /> | |||
</target> | |||
</project> |
@@ -69,6 +69,11 @@ public abstract class AbstractSvnTask extends Task { | |||
*/ | |||
private boolean quiet = false; | |||
/** | |||
* be verbose | |||
*/ | |||
private boolean verbose = false; | |||
/** | |||
* report only, don't change any files. | |||
*/ | |||
@@ -466,6 +471,14 @@ public abstract class AbstractSvnTask extends Task { | |||
quiet = q; | |||
} | |||
/** | |||
* If true, be verbose. | |||
* @param q if true, be verbose. | |||
*/ | |||
public void setVerbose(boolean v) { | |||
verbose = v; | |||
} | |||
/** | |||
* If true, report only and don't change any files. | |||
* | |||
@@ -523,7 +536,7 @@ public abstract class AbstractSvnTask extends Task { | |||
* <li> | |||
* quiet | |||
* </li> | |||
* <li>svnroot</li> | |||
* <li>verbose</li> | |||
* <li>dryrun</li> | |||
* </ul> | |||
*/ | |||
@@ -535,6 +548,9 @@ public abstract class AbstractSvnTask extends Task { | |||
if (quiet) { | |||
c.createArgument(true).setValue("--quiet"); | |||
} | |||
if (verbose) { | |||
c.createArgument(true).setValue("--verbose"); | |||
} | |||
if (dryrun) { | |||
c.createArgument(true).setValue("--dry-run"); | |||
} | |||
@@ -0,0 +1,134 @@ | |||
/* | |||
* 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.ByteArrayOutputStream; | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
/** | |||
* Invokes {@link #processLine processLine} whenever a full line has | |||
* been written to this stream. | |||
* | |||
* <p>Tries to be smart about line separators.</p> | |||
*/ | |||
public abstract class LineOrientedOutputStream extends OutputStream { | |||
/** Initial buffer size. */ | |||
private static final int INTIAL_SIZE = 132; | |||
/** Carriage return */ | |||
private static final int CR = 0x0d; | |||
/** Linefeed */ | |||
private static final int LF = 0x0a; | |||
private ByteArrayOutputStream buffer | |||
= new ByteArrayOutputStream(INTIAL_SIZE); | |||
private boolean skip = false; | |||
/** | |||
* Write the data to the buffer and flush the buffer, if a line | |||
* separator is detected. | |||
* | |||
* @param cc data to log (byte). | |||
*/ | |||
public final void write(int cc) throws IOException { | |||
final byte c = (byte) cc; | |||
if ((c == '\n') || (c == '\r')) { | |||
if (!skip) { | |||
processBuffer(); | |||
} | |||
} else { | |||
buffer.write(cc); | |||
} | |||
skip = (c == '\r'); | |||
} | |||
/** | |||
* Flush this log stream | |||
*/ | |||
public final void flush() throws IOException { | |||
if (buffer.size() > 0) { | |||
processBuffer(); | |||
} | |||
} | |||
/** | |||
* Converts the buffer to a string and sends it to | |||
* <code>processLine</code> | |||
*/ | |||
private void processBuffer() throws IOException { | |||
try { | |||
processLine(buffer.toString()); | |||
} finally { | |||
buffer.reset(); | |||
} | |||
} | |||
/** | |||
* Processes a line. | |||
* | |||
* @param line the line to log. | |||
*/ | |||
protected abstract void processLine(String line) throws IOException; | |||
/** | |||
* Writes all remaining | |||
*/ | |||
public final void close() throws IOException { | |||
if (buffer.size() > 0) { | |||
processBuffer(); | |||
} | |||
super.close(); | |||
} | |||
/** | |||
* Write a block of characters to the output stream | |||
* | |||
* @param b the array containing the data | |||
* @param off the offset into the array where data starts | |||
* @param len the length of block | |||
* | |||
* @throws IOException if the data cannot be written into the stream. | |||
*/ | |||
public final void write(byte[] b, int off, int len) throws IOException { | |||
// find the line breaks and pass other chars through in blocks | |||
int offset = off; | |||
int blockStartOffset = offset; | |||
int remaining = len; | |||
while (remaining > 0) { | |||
while (remaining > 0 && b[offset] != LF && b[offset] != CR) { | |||
offset++; | |||
remaining--; | |||
} | |||
// either end of buffer or a line separator char | |||
int blockLength = offset - blockStartOffset; | |||
if (blockLength > 0) { | |||
buffer.write(b, blockStartOffset, blockLength); | |||
} | |||
while (remaining > 0 && (b[offset] == LF || b[offset] == CR)) { | |||
write(b[offset]); | |||
offset++; | |||
remaining--; | |||
} | |||
blockStartOffset = offset; | |||
} | |||
} | |||
} |
@@ -0,0 +1,188 @@ | |||
/* | |||
* 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.text.ParseException; | |||
import java.text.SimpleDateFormat; | |||
import java.util.Date; | |||
import java.util.ArrayList; | |||
/** | |||
* A class used to parse the output of the svn log command. | |||
* | |||
* @version $Revision$ $Date$ | |||
*/ | |||
class SvnChangeLogParser extends LineOrientedOutputStream { | |||
private final static int GET_ENTRY_LINE = 0; | |||
private final static int GET_REVISION_LINE = 1; | |||
private final static int GET_PATHS = 2; | |||
private final static int GET_MESSAGE = 3; | |||
private String message = ""; | |||
private Date date = null; | |||
private String author = null; | |||
private String revision = null; | |||
private ArrayList paths = new ArrayList(); | |||
/** input format for dates read in from cvs log */ | |||
private static final String PATTERN = "yyyy-MM-dd HH:mm:ss"; | |||
private static final SimpleDateFormat INPUT_DATE | |||
= new SimpleDateFormat(PATTERN); | |||
private final ArrayList entries = new ArrayList(); | |||
private int status = GET_ENTRY_LINE; | |||
/** | |||
* Get a list of rcs entries as an array. | |||
* | |||
* @return a list of rcs entries as an array | |||
*/ | |||
public SvnEntry[] getEntrySetAsArray() { | |||
return (SvnEntry[]) entries.toArray(new SvnEntry[entries.size()]); | |||
} | |||
/** | |||
* Receive notification about the process writing | |||
* to standard output. | |||
* @param line the line to process | |||
*/ | |||
public void processLine(final String line) { | |||
switch(status) { | |||
case GET_ENTRY_LINE: | |||
// make sure attributes are reset when | |||
// working on a 'new' file. | |||
reset(); | |||
processEntryStart(line); | |||
break; | |||
case GET_REVISION_LINE: | |||
processRevision(line); | |||
break; | |||
case GET_MESSAGE: | |||
processMessage(line); | |||
break; | |||
case GET_PATHS: | |||
processPath(line); | |||
break; | |||
default: | |||
// Do nothing | |||
break; | |||
} | |||
} | |||
/** | |||
* Process a line while in "GET_MESSAGE" state. | |||
* | |||
* @param line the line | |||
*/ | |||
private void processMessage(final String line) { | |||
final String lineSeparator = System.getProperty("line.separator"); | |||
if (line.equals("------------------------------------------------------------------------")) { | |||
//We have ended changelog for that particular revision | |||
//so we can save it | |||
final int end | |||
= message.length() - lineSeparator.length(); //was -1 | |||
message = message.substring(0, end); | |||
saveEntry(); | |||
status = GET_REVISION_LINE; | |||
} else { | |||
message += line + lineSeparator; | |||
} | |||
} | |||
/** | |||
* Process a line while in "GET_ENTRY_LINE" state. | |||
* | |||
* @param line the line to process | |||
*/ | |||
private void processEntryStart(final String line) { | |||
if (line.equals("------------------------------------------------------------------------")) { | |||
status = GET_REVISION_LINE; | |||
} | |||
} | |||
/** | |||
* Process a line while in "REVISION" state. | |||
* | |||
* @param line the line to process | |||
*/ | |||
private void processRevision(final String line) { | |||
int index = line.indexOf(" |"); | |||
if (line.startsWith("r") | |||
&& (line.endsWith("lines") || line.endsWith("line")) | |||
&& index > -1) { | |||
revision = line.substring(1, index); | |||
int end = line.indexOf(" |", index + 1); | |||
author = line.substring(index + 3, end); | |||
String d = line.substring(end + 3, end + 3 + PATTERN.length()); | |||
date = parseDate(d); | |||
status = GET_PATHS; | |||
} | |||
} | |||
/** | |||
* Process a line while in "GET_PATHS" state. | |||
* | |||
* @param line the line to process | |||
*/ | |||
private void processPath(final String line) { | |||
if (line.startsWith("Changed paths:")) { | |||
// ignore | |||
} else if (line.equals("")) { | |||
status = GET_MESSAGE; | |||
} else { | |||
paths.add(line.substring(5)); | |||
} | |||
} | |||
/** | |||
* Utility method that saves the current entry. | |||
*/ | |||
private void saveEntry() { | |||
SvnEntry entry = new SvnEntry(date, revision, author, message, | |||
paths); | |||
entries.add(entry); | |||
} | |||
/** | |||
* Parse date out from expected format. | |||
* | |||
* @param date the string holding date | |||
* @return the date object or null if unknown date format | |||
*/ | |||
private Date parseDate(final String date) { | |||
try { | |||
return INPUT_DATE.parse(date); | |||
} catch (ParseException e) { | |||
return null; | |||
} | |||
} | |||
/** | |||
* Reset all internal attributes except status. | |||
*/ | |||
public void reset() { | |||
this.date = null; | |||
this.author = null; | |||
this.message = ""; | |||
this.revision = null; | |||
this.paths.clear(); | |||
} | |||
} |
@@ -0,0 +1,398 @@ | |||
/* | |||
* 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.File; | |||
import java.io.FileInputStream; | |||
import java.io.FileOutputStream; | |||
import java.io.IOException; | |||
import java.io.OutputStreamWriter; | |||
import java.io.PrintWriter; | |||
import java.io.UnsupportedEncodingException; | |||
import java.text.ParseException; | |||
import java.text.SimpleDateFormat; | |||
import java.util.Date; | |||
import java.util.Enumeration; | |||
import java.util.Properties; | |||
import java.util.Vector; | |||
import org.apache.tools.ant.BuildException; | |||
import org.apache.tools.ant.DirectoryScanner; | |||
import org.apache.tools.ant.Project; | |||
import org.apache.tools.ant.taskdefs.LogOutputStream; | |||
import org.apache.tools.ant.taskdefs.PumpStreamHandler; | |||
import org.apache.tools.ant.taskdefs.cvslib.CvsUser; | |||
import org.apache.tools.ant.types.FileSet; | |||
import org.apache.tools.ant.util.FileUtils; | |||
/** | |||
* Examines the output of svn log and group related changes together. | |||
* | |||
* It produces an XML output representing the list of changes. | |||
* <pre> | |||
* <font color=#0000ff><!-- Root element --></font> | |||
* <font color=#6a5acd><!ELEMENT</font> changelog <font color=#ff00ff>(entry</font><font color=#ff00ff>+</font><font color=#ff00ff>)</font><font color=#6a5acd>></font> | |||
* <font color=#0000ff><!-- SVN Entry --></font> | |||
* <font color=#6a5acd><!ELEMENT</font> entry <font color=#ff00ff>(date,time,revision,author,file</font><font color=#ff00ff>+,msg</font><font color=#ff00ff>,msg)</font><font color=#6a5acd>></font> | |||
* <font color=#0000ff><!-- Date of svn entry --></font> | |||
* <font color=#6a5acd><!ELEMENT</font> date <font color=#ff00ff>(#PCDATA)</font><font color=#6a5acd>></font> | |||
* <font color=#0000ff><!-- Time of svn entry --></font> | |||
* <font color=#6a5acd><!ELEMENT</font> time <font color=#ff00ff>(#PCDATA)</font><font color=#6a5acd>></font> | |||
* <font color=#0000ff><!-- Author of change --></font> | |||
* <font color=#6a5acd><!ELEMENT</font> author <font color=#ff00ff>(#PCDATA)</font><font color=#6a5acd>></font> | |||
* <font color=#0000ff><!-- commit message --></font> | |||
* <font color=#6a5acd><!ELEMENT</font> msg <font color=#ff00ff>(#PCDATA)</font><font color=#6a5acd>></font> | |||
* <font color=#0000ff><!-- List of files affected --></font> | |||
* <font color=#6a5acd><!ELEMENT</font> file <font color=#ff00ff>(name</font><font color=#ff00ff>?</font><font color=#ff00ff>)</font><font color=#6a5acd>></font> | |||
* <font color=#0000ff><!-- Name of the file --></font> | |||
* <font color=#6a5acd><!ELEMENT</font> name <font color=#ff00ff>(#PCDATA)</font><font color=#6a5acd>></font> | |||
* <font color=#0000ff><!-- Revision number --></font> | |||
* <font color=#6a5acd><!ELEMENT</font> revision <font color=#ff00ff>(#PCDATA)</font><font color=#6a5acd>></font> | |||
* </pre> | |||
* | |||
* @ant.task name="svnchangelog" category="scm" | |||
*/ | |||
public class SvnChangeLogTask extends AbstractSvnTask { | |||
/** User list */ | |||
private File usersFile; | |||
/** User list */ | |||
private Vector svnUsers = new Vector(); | |||
/** Input dir */ | |||
private File inputDir; | |||
/** Output file */ | |||
private File destFile; | |||
/** The earliest revision at which to start processing entries. */ | |||
private String startRevision; | |||
/** The latest revision at which to stop processing entries. */ | |||
private String endRevision; | |||
/** | |||
* Filesets containing list of files against which the svn log will be | |||
* performed. If empty then all files in the working directory will | |||
* be checked. | |||
*/ | |||
private final Vector filesets = new Vector(); | |||
/** | |||
* Set the base dir for svn. | |||
* | |||
* @param inputDir The new dir value | |||
*/ | |||
public void setDir(final File inputDir) { | |||
this.inputDir = inputDir; | |||
} | |||
/** | |||
* Set the output file for the log. | |||
* | |||
* @param destFile The new destfile value | |||
*/ | |||
public void setDestfile(final File destFile) { | |||
this.destFile = destFile; | |||
} | |||
/** | |||
* Set a lookup list of user names & addresses | |||
* | |||
* @param usersFile The file containing the users info. | |||
*/ | |||
public void setUsersfile(final File usersFile) { | |||
this.usersFile = usersFile; | |||
} | |||
/** | |||
* Add a user to list changelog knows about. | |||
* | |||
* @param user the user | |||
*/ | |||
public void addUser(final CvsUser user) { | |||
svnUsers.addElement(user); | |||
} | |||
/** | |||
* Set the revision at which the changelog should start. | |||
* | |||
* @param start The revision at which the changelog should start. | |||
*/ | |||
public void setStart(final String start) { | |||
this.startRevision = start; | |||
} | |||
/** | |||
* Set the revision at which the changelog should stop. | |||
* | |||
* @param endRevision The revision at which the changelog should stop. | |||
*/ | |||
public void setEnd(final String endRevision) { | |||
this.endRevision = endRevision; | |||
} | |||
/** | |||
* Set the number of days worth of log entries to process. | |||
* | |||
* @param days the number of days of log to process. | |||
*/ | |||
public void setDaysinpast(final int days) { | |||
final long time = System.currentTimeMillis() | |||
- (long) days * 24 * 60 * 60 * 1000; | |||
final SimpleDateFormat outputDate = | |||
new SimpleDateFormat("{yyyy-MM-dd}"); | |||
setStart(outputDate.format(new Date(time))); | |||
} | |||
/** | |||
* Adds a set of files about which svn logs will be generated. | |||
* | |||
* @param fileSet a set of files about which svn logs will be generated. | |||
*/ | |||
public void addFileset(final FileSet fileSet) { | |||
filesets.addElement(fileSet); | |||
} | |||
/** | |||
* Execute task | |||
* | |||
* @exception BuildException if something goes wrong executing the | |||
* svn command | |||
*/ | |||
public void execute() throws BuildException { | |||
File savedDir = inputDir; // may be altered in validate | |||
try { | |||
validate(); | |||
final Properties userList = new Properties(); | |||
loadUserlist(userList); | |||
for (int i = 0, size = svnUsers.size(); i < size; i++) { | |||
final CvsUser user = (CvsUser) svnUsers.get(i); | |||
user.validate(); | |||
userList.put(user.getUserID(), user.getDisplayname()); | |||
} | |||
setSubCommand("log"); | |||
setVerbose(true); | |||
if (null != startRevision) { | |||
if (null != endRevision) { | |||
setRevision(startRevision + ":" + endRevision); | |||
} else { | |||
setRevision(startRevision + ":HEAD"); | |||
} | |||
} | |||
// Check if list of files to check has been specified | |||
if (!filesets.isEmpty()) { | |||
final Enumeration e = filesets.elements(); | |||
while (e.hasMoreElements()) { | |||
final FileSet fileSet = (FileSet) e.nextElement(); | |||
final DirectoryScanner scanner = | |||
fileSet.getDirectoryScanner(getProject()); | |||
final String[] files = scanner.getIncludedFiles(); | |||
for (int i = 0; i < files.length; i++) { | |||
addSubCommandArgument(files[i]); | |||
} | |||
} | |||
} | |||
final SvnChangeLogParser parser = new SvnChangeLogParser(); | |||
final PumpStreamHandler handler = | |||
new PumpStreamHandler(parser, | |||
new LogOutputStream(this, | |||
Project.MSG_ERR)); | |||
log(getSubCommand(), Project.MSG_VERBOSE); | |||
setDest(inputDir); | |||
setExecuteStreamHandler(handler); | |||
super.execute(); | |||
final SvnEntry[] entrySet = parser.getEntrySetAsArray(); | |||
final SvnEntry[] filteredEntrySet = filterEntrySet(entrySet); | |||
replaceAuthorIdWithName(userList, filteredEntrySet); | |||
writeChangeLog(filteredEntrySet); | |||
} finally { | |||
inputDir = savedDir; | |||
} | |||
} | |||
/** | |||
* Validate the parameters specified for task. | |||
* | |||
* @throws BuildException if fails validation checks | |||
*/ | |||
private void validate() | |||
throws BuildException { | |||
if (null == inputDir) { | |||
inputDir = getDest(); | |||
} | |||
if (null == destFile) { | |||
final String message = "Destfile must be set."; | |||
throw new BuildException(message); | |||
} | |||
if (!inputDir.exists()) { | |||
final String message = "Cannot find base dir " | |||
+ inputDir.getAbsolutePath(); | |||
throw new BuildException(message); | |||
} | |||
if (null != usersFile && !usersFile.exists()) { | |||
final String message = "Cannot find user lookup list " | |||
+ usersFile.getAbsolutePath(); | |||
throw new BuildException(message); | |||
} | |||
} | |||
/** | |||
* Load the userlist from the userList file (if specified) and add to | |||
* list of users. | |||
* | |||
* @param userList the file of users | |||
* @throws BuildException if file can not be loaded for some reason | |||
*/ | |||
private void loadUserlist(final Properties userList) | |||
throws BuildException { | |||
if (null != usersFile) { | |||
try { | |||
userList.load(new FileInputStream(usersFile)); | |||
} catch (final IOException ioe) { | |||
throw new BuildException(ioe.toString(), ioe); | |||
} | |||
} | |||
} | |||
/** | |||
* Filter the specified entries according to an appropriate rule. | |||
* | |||
* @param entrySet the entry set to filter | |||
* @return the filtered entry set | |||
*/ | |||
private SvnEntry[] filterEntrySet(final SvnEntry[] entrySet) { | |||
final Vector results = new Vector(); | |||
for (int i = 0; i < entrySet.length; i++) { | |||
final SvnEntry svnEntry = entrySet[i]; | |||
if (null != endRevision && !isBeforeEndRevision(svnEntry)) { | |||
//Skip revisions that are too late | |||
continue; | |||
} | |||
results.addElement(svnEntry); | |||
} | |||
final SvnEntry[] resultArray = new SvnEntry[results.size()]; | |||
results.copyInto(resultArray); | |||
return resultArray; | |||
} | |||
/** | |||
* replace all known author's id's with their maven specified names | |||
*/ | |||
private void replaceAuthorIdWithName(final Properties userList, | |||
final SvnEntry[] entrySet) { | |||
for (int i = 0; i < entrySet.length; i++) { | |||
final SvnEntry entry = entrySet[ i ]; | |||
if (userList.containsKey(entry.getAuthor())) { | |||
entry.setAuthor(userList.getProperty(entry.getAuthor())); | |||
} | |||
} | |||
} | |||
/** | |||
* Print changelog to file specified in task. | |||
* | |||
* @param entrySet the entry set to write. | |||
* @throws BuildException if there is an error writing changelog. | |||
*/ | |||
private void writeChangeLog(final SvnEntry[] entrySet) | |||
throws BuildException { | |||
FileOutputStream output = null; | |||
try { | |||
output = new FileOutputStream(destFile); | |||
final PrintWriter writer = | |||
new PrintWriter(new OutputStreamWriter(output, "UTF-8")); | |||
final SvnChangeLogWriter serializer = new SvnChangeLogWriter(); | |||
serializer.printChangeLog(writer, entrySet); | |||
} catch (final UnsupportedEncodingException uee) { | |||
getProject().log(uee.toString(), Project.MSG_ERR); | |||
} catch (final IOException ioe) { | |||
throw new BuildException(ioe.toString(), ioe); | |||
} finally { | |||
FileUtils.close(output); | |||
} | |||
} | |||
private static final String PATTERN = "yyyy-MM-dd"; | |||
private static final SimpleDateFormat INPUT_DATE | |||
= new SimpleDateFormat(PATTERN); | |||
/** | |||
* Checks whether a given entry is before the given end revision, | |||
* using revision numbers or date information as appropriate. | |||
*/ | |||
private boolean isBeforeEndRevision(SvnEntry entry) { | |||
if (endRevision.startsWith("{") | |||
&& endRevision.length() >= 2 + PATTERN.length() ) { | |||
try { | |||
Date endDate = | |||
INPUT_DATE.parse(endRevision.substring(1, | |||
PATTERN.length() | |||
+ 1)); | |||
return entry.getDate().before(endDate); | |||
} catch (ParseException e) { | |||
} | |||
} else { | |||
try { | |||
int endRev = Integer.parseInt(endRevision); | |||
int entryRev = Integer.parseInt(entry.getRevision()); | |||
return endRev >= entryRev; | |||
} catch (NumberFormatException e) { | |||
} // end of try-catch | |||
} | |||
// failed to parse revision, use a save fallback | |||
return true; | |||
} | |||
} | |||
@@ -0,0 +1,81 @@ | |||
/* | |||
* 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.PrintWriter; | |||
import java.text.SimpleDateFormat; | |||
/** | |||
* Class used to generate an XML changelog. | |||
*/ | |||
public class SvnChangeLogWriter { | |||
/** output format for dates written to xml file */ | |||
private static final SimpleDateFormat OUTPUT_DATE | |||
= new SimpleDateFormat("yyyy-MM-dd"); | |||
/** output format for times written to xml file */ | |||
private static final SimpleDateFormat OUTPUT_TIME | |||
= new SimpleDateFormat("HH:mm"); | |||
/** | |||
* Print out the specified entries. | |||
* | |||
* @param output writer to which to send output. | |||
* @param entries the entries to be written. | |||
*/ | |||
public void printChangeLog(final PrintWriter output, | |||
final SvnEntry[] entries) { | |||
output.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); | |||
output.println("<changelog>"); | |||
for (int i = 0; i < entries.length; i++) { | |||
final SvnEntry entry = entries[i]; | |||
printEntry(output, entry); | |||
} | |||
output.println("</changelog>"); | |||
output.flush(); | |||
output.close(); | |||
} | |||
/** | |||
* Print out an individual entry in changelog. | |||
* | |||
* @param entry the entry to print | |||
* @param output writer to which to send output. | |||
*/ | |||
private void printEntry(final PrintWriter output, final SvnEntry entry) { | |||
output.println("\t<entry>"); | |||
output.println("\t\t<date>" + OUTPUT_DATE.format(entry.getDate()) | |||
+ "</date>"); | |||
output.println("\t\t<time>" + OUTPUT_TIME.format(entry.getDate()) | |||
+ "</time>"); | |||
output.println("\t\t<author><![CDATA[" + entry.getAuthor() | |||
+ "]]></author>"); | |||
output.println("\t\t<revision><![CDATA[" + entry.getRevision() | |||
+ "]]></revision>"); | |||
String[] paths = entry.getPaths(); | |||
for (int i = 0; i < paths.length; i++) { | |||
output.println("\t\t<file>"); | |||
output.println("\t\t\t<name><![CDATA[" + paths[i] + "]]></name>"); | |||
output.println("\t\t</file>"); | |||
} | |||
output.println("\t\t<msg><![CDATA[" + entry.getMessage() + "]]></msg>"); | |||
output.println("\t</entry>"); | |||
} | |||
} | |||
@@ -0,0 +1,115 @@ | |||
/* | |||
* 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.util.ArrayList; | |||
import java.util.Collection; | |||
import java.util.Collections; | |||
import java.util.Date; | |||
public class SvnEntry { | |||
private final Date date; | |||
private final String revision; | |||
private String author; | |||
private final String message; | |||
private final ArrayList paths = new ArrayList(); | |||
/** | |||
* Creates a new instance of a SvnEntry | |||
* @param date the date | |||
* @param author the author | |||
* @param message a message to be added to the revision | |||
*/ | |||
public SvnEntry(final Date date, final String revision, | |||
final String author, final String message) { | |||
this(date, revision, author, message, Collections.EMPTY_LIST); | |||
} | |||
/** | |||
* Creates a new instance of a SvnEntry | |||
* @param date the date | |||
* @param author the author | |||
* @param message a message to be added to the revision | |||
*/ | |||
public SvnEntry(final Date date, final String revision, | |||
final String author, final String message, | |||
final Collection paths) { | |||
this.date = date; | |||
this.revision = revision; | |||
this.author = author; | |||
this.message = message; | |||
this.paths.addAll(paths); | |||
} | |||
/** | |||
* Adds a path to the SvnEntry | |||
* @param path the path to add | |||
* @param revision the revision | |||
*/ | |||
public void addPath(final String name) { | |||
paths.add(name); | |||
} | |||
/** | |||
* Gets the date of the SvnEntry | |||
* @return the date | |||
*/ | |||
public Date getDate() { | |||
return date; | |||
} | |||
/** | |||
* Gets the revision of the SvnEntry | |||
* @return the date | |||
*/ | |||
public String getRevision() { | |||
return revision; | |||
} | |||
/** | |||
* Sets the author of the SvnEntry | |||
* @param author the author | |||
*/ | |||
public void setAuthor(final String author) { | |||
this.author = author; | |||
} | |||
/** | |||
* Gets the author of the SvnEntry | |||
* @return the author | |||
*/ | |||
public String getAuthor() { | |||
return author; | |||
} | |||
/** | |||
* Gets the message for the SvnEntry | |||
* @return the message | |||
*/ | |||
public String getMessage() { | |||
return message; | |||
} | |||
/** | |||
* Gets the paths in this SvnEntry | |||
* @return the files | |||
*/ | |||
public String[] getPaths() { | |||
return (String[]) paths.toArray(new String[paths.size()]); | |||
} | |||
} |
@@ -19,4 +19,8 @@ | |||
name="svn" | |||
classname="org.apache.tools.ant.taskdefs.svn.Svn" | |||
/> | |||
<taskdef | |||
name="changelog" | |||
classname="org.apache.tools.ant.taskdefs.svn.SvnChangeLogTask" | |||
/> | |||
</antlib> |