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