diff --git a/WHATSNEW b/WHATSNEW
index a26e0d129..018768dba 100644
--- a/WHATSNEW
+++ b/WHATSNEW
@@ -13,7 +13,7 @@ Changes that could break older environments:
Other changes:
--------------
-* New tasks: ear, p4counter
+* New tasks: ear, p4counter, recorder
* Ant now uses JAXP 1.1
diff --git a/docs/manual/CoreTasks/recorder.html b/docs/manual/CoreTasks/recorder.html
new file mode 100644
index 000000000..32b5e3e35
--- /dev/null
+++ b/docs/manual/CoreTasks/recorder.html
@@ -0,0 +1,158 @@
+
+
+
+
+Ant User Manual
+
+
+
+
+
+Description
+A recorder is a listener to the current build process that records the
+output to a file.
+
+
Several recorders can exist at the same time. Each recorder is
+associated with a file. The filename is used as a unique identifier for
+the recorders. The first call to the recorder task with an unused filename
+will create a recorder (using the parameters provided) and add it to the
+listeners of the build. All subsiquent calls to the recorder task using
+this filename will modify that recorders state (recording or not) or other
+properties (like logging level).
+
+
Some technical issues: the file's print stream is flushed for "finished"
+events (buildFinished, targetFinished and taskFinished), and is closed on
+a buildFinished event.
+
+
Parameters
+
+
+ Attribute |
+ Description |
+ Required |
+
+
+ name |
+ The name of the file this logger is associated with. |
+ yes |
+
+
+ action |
+ This tells the logger what to do: should it start
+ recording or stop? The first time that the recorder task is called for
+ this logfile, and if this attribute is not provided, then the default
+ for this attribute is "start". If this attribute is not provided on
+ subsiquest calls, then the state remains as previous.
+ [Values = {start|stop}, Default = no state change] |
+ no |
+
+
+ append |
+ Should the recorder append to a file, or create a new
+ one? This is only applicable the first time this task is called for
+ this file. [Vaules = {yes|no}, Default=yes] |
+ no |
+
+
+ loglevel |
+ At what logging level should this recorder instance
+ record to? This is not a once only parameter (like append
+ is) -- you can increase or decrease the logging level as the build process
+ continues. [Vaules= {error|warn|info|verbose|debug}, Default = no change]
+ |
+ no |
+
+
+
+Examples
+The following build.xml snippit is an example of how to use the recorder
+to record just the <javac>
task:
+
+ ...
+ <compile >
+ <recorder name="log.txt" action="start" />
+ <javac ...
+ <recorder name="log.txt" action="stop" />
+ <compile/>
+ ...
+
+
+The following two calls to <recorder>
set up two
+recorders: one to file "records-simple.log" at logging level info
+(the default) and one to file "ISO.log" using logging level of
+verbose
.
+
+ ...
+ <recorder name="records-simple.log" />
+ <recorder name="ISO.log" loglevel="verbose" />
+ ...
+
+
+Notes
+There is some funtionality that I would like to be able to add in the
+future. They include things like the following:
+
+
+ Attribute |
+ Description |
+ Required |
+
+
+ messageprefix |
+ Whether or not to include the message prefixes (things
+ like the name of the tasks or targets, etc). This has the same effect as
+ the -emacs command line parameter does to the screen output.
+ [yes|no] |
+ no |
+
+
+ listener |
+ A classname of a build listener to use from this point
+ on instead of the default listener. |
+ no |
+
+
+ includetarget |
+ A comma-separated list of targets to automaticly
+ record. If this value is "all", then all targets are recorded.
+ [Default = all] |
+ no |
+
+
+ excludetarget |
+ no |
+
+
+ includetask |
+ A comma-separated list of task to automaticly
+ record or not. This could be difficult as it could conflict with the
+ includetarget/excludetarget . (e.g.:
+ includetarget="compile" exlcudetask="javac" , what should
+ happen?) |
+ no |
+
+
+ excludetask |
+ no |
+
+
+ action |
+ add greater flexability to the action attribute. Things
+ like close to close the print stream. |
+ no |
+
+
+ |
+ |
+ |
+
+
+
+
+
+
Copyright © 2000,2001 Apache Software Foundation. All rights
+Reserved.
+
+
+
+
diff --git a/docs/manual/coretasklist.html b/docs/manual/coretasklist.html
index 93b002468..6a6031906 100644
--- a/docs/manual/coretasklist.html
+++ b/docs/manual/coretasklist.html
@@ -49,6 +49,7 @@
Move
Patch
Property
+Recorder
Rename
Replace
Rmic
diff --git a/src/main/org/apache/tools/ant/taskdefs/Recorder.java b/src/main/org/apache/tools/ant/taskdefs/Recorder.java
new file mode 100644
index 000000000..314033817
--- /dev/null
+++ b/src/main/org/apache/tools/ant/taskdefs/Recorder.java
@@ -0,0 +1,230 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 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;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.*;
+import org.apache.tools.ant.util.*;
+import org.apache.tools.ant.taskdefs.compilers.*;
+import org.apache.tools.ant.Task;
+
+import java.io.*;
+
+import java.util.*;
+
+/**
+ * This task is the manager for RecorderEntry's. It is this class
+ * that holds all entries, modifies them every time the
+ * task is called, and addes them to the build listener process.
+ * @see RecorderEntry
+ * @author J D Glanville
+ * @version 0.5
+ *
+ */
+public class Recorder extends Task {
+
+ //////////////////////////////////////////////////////////////////////
+ // ATTRIBUTES
+
+ /** The name of the file to record to. */
+ private String filename = null;
+ /** Whether or not to append. Need Boolean to record an unset
+ * state (null).
+ */
+ private Boolean append = null;
+ /** Whether to start or stop recording. Need Boolean to record an
+ * unset state (null).
+ */
+ private Boolean start = null;
+ /** What level to log? -1 means not initialized yet. */
+ private int loglevel = -1;
+ /** The list of recorder entries. */
+ private static HashMap recorderEntries = new HashMap();
+
+ //////////////////////////////////////////////////////////////////////
+ // CONSTRUCTORS / INITIALIZERS
+
+ //////////////////////////////////////////////////////////////////////
+ // ACCESSOR METHODS
+
+ /**
+ * Sets the name of the file to log to, and the name of the recorder entry.
+ * @param fname File name of logfile.
+ */
+ public void setName( String fname ) {
+ filename = fname;
+ }
+
+ /**
+ * Sets the action for the associated recorder entry.
+ * @param action The action for the entry to take: start or stop.
+ */
+ public void setAction( ActionChoices action ) {
+ if ( action.getValue().equalsIgnoreCase( "start" ) ) {
+ start = Boolean.TRUE;
+ } else {
+ start = Boolean.FALSE;
+ }
+ }
+
+ /**
+ * Whether or not the logger should append to a previous file.
+ */
+ public void setAppend( boolean append ) {
+ this.append = new Boolean(append);
+ }
+
+ /**
+ * Sets the level to which this recorder entry should log to.
+ * @see VerbosityLevelChoices
+ */
+ public void setLoglevel( VerbosityLevelChoices level ){
+ //I hate cascading if/elseif clauses !!!
+ String lev = level.getValue();
+ if ( lev.equalsIgnoreCase("error") ) {
+ loglevel = Project.MSG_ERR;
+ } else if ( lev.equalsIgnoreCase("warn") ){
+ loglevel = Project.MSG_WARN;
+ } else if ( lev.equalsIgnoreCase("info") ){
+ loglevel = Project.MSG_INFO;
+ } else if ( lev.equalsIgnoreCase("verbose") ){
+ loglevel = Project.MSG_VERBOSE;
+ } else if ( lev.equalsIgnoreCase("debug") ){
+ loglevel = Project.MSG_DEBUG;
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ // CORE / MAIN BODY
+
+ /**
+ * The main execution.
+ */
+ public void execute() throws BuildException {
+ if ( filename == null )
+ throw new BuildException( "No filename specified" );
+
+ getProject().log( "setting a recorder for name " + filename,
+ Project.MSG_DEBUG );
+
+ // get the recorder entry
+ RecorderEntry recorder = getRecorder( filename, getProject() );
+ // set the values on the recorder
+ recorder.setMessageOutputLevel( loglevel );
+ recorder.setRecordState( start );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ // INNER CLASSES
+
+ /**
+ * A list of possible values for the setAction()
method.
+ * Possible values include: start and stop.
+ */
+ public static class ActionChoices extends EnumeratedAttribute {
+ private static final String[] values = {"start", "stop"};
+ public String[] getValues() {
+ return values;
+ }
+ }
+
+ /**
+ * A list of possible values for the setLoglevel()
method.
+ * Possible values include: error, warn, info, verbose, debug.
+ */
+ public static class VerbosityLevelChoices extends EnumeratedAttribute {
+ private static final String[] values = { "error", "warn", "info",
+ "verbose", "debug"};
+ public String[] getValues() {
+ return values;
+ }
+ }
+
+ /**
+ * Gets the recorder that's associated with the passed in name.
+ * If the recorder doesn't exist, then a new one is created.
+ */
+ protected RecorderEntry getRecorder( String name, Project proj ) throws BuildException {
+ Object o = recorderEntries.get(name);
+ RecorderEntry entry;
+ if ( o == null ) {
+ // create a recorder entry
+ try {
+ entry = new RecorderEntry( name );
+ PrintStream out = null;
+ if ( append == null ) {
+ out = new PrintStream(
+ new FileOutputStream(name));
+ } else {
+ out = new PrintStream(
+ new FileOutputStream(name, append.booleanValue()));
+ }
+ entry.setErrorPrintStream(out);
+ entry.setOutputPrintStream(out);
+ } catch ( IOException ioe ) {
+ throw new BuildException( "Problems creating a recorder entry",
+ ioe );
+ }
+ proj.addBuildListener(entry);
+ recorderEntries.put(name, entry);
+ } else {
+ entry = (RecorderEntry) o;
+ }
+ return entry;
+ }
+
+}
diff --git a/src/main/org/apache/tools/ant/taskdefs/RecorderEntry.java b/src/main/org/apache/tools/ant/taskdefs/RecorderEntry.java
new file mode 100644
index 000000000..6ca3acab8
--- /dev/null
+++ b/src/main/org/apache/tools/ant/taskdefs/RecorderEntry.java
@@ -0,0 +1,230 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 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;
+
+import org.apache.tools.ant.*;
+import java.io.*;
+import java.util.*;
+
+/**
+ * This is a class that represents a recorder. This is the listener
+ * to the build process.
+ * @author J D Glanville
+ * @version 0.5
+ *
+ */
+public class RecorderEntry implements BuildLogger {
+
+ //////////////////////////////////////////////////////////////////////
+ // ATTRIBUTES
+
+ /**
+ * The name of the file associated with this recorder entry.
+ */
+ private String filename = null;
+ /**
+ * The state of the recorder (recorder on or off).
+ */
+ private boolean record = true;
+ /**
+ * The current verbosity level to record at.
+ */
+ private int loglevel = Project.MSG_INFO;
+ /**
+ * The output PrintStream to record to.
+ */
+ private PrintStream out = null;
+ /**
+ * The start time of the last know target.
+ */
+ private long targetStartTime = 0l;
+ /**
+ * Line separator.
+ */
+ private static String lSep = System.getProperty("line.separator");
+
+ //////////////////////////////////////////////////////////////////////
+ // CONSTRUCTORS / INITIALIZERS
+
+ /**
+ * @param name The name of this recorder (used as the filename).
+ *
+ */
+ protected RecorderEntry( String name ) {
+ filename = name;
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ // ACCESSOR METHODS
+
+ /**
+ * @return the name of the file the output is sent to.
+ */
+ public String getFilename() {
+ return filename;
+ }
+
+ /**
+ * Turns off or on this recorder.
+ * @param state true for on, false for off, null for no change.
+ */
+ public void setRecordState( Boolean state ) {
+ if ( state != null )
+ record = state.booleanValue();
+ }
+
+ public void buildStarted(BuildEvent event) {
+ log( "> BUILD STARTED", Project.MSG_DEBUG );
+ }
+
+ public void buildFinished(BuildEvent event) {
+ log( "< BUILD FINISHED", Project.MSG_DEBUG );
+
+ Throwable error = event.getException();
+ if (error == null) {
+ out.println(lSep + "BUILD SUCCESSFUL");
+ } else {
+ out.println(lSep + "BUILD FAILED" + lSep);
+ error.printStackTrace(out);
+ }
+ out.flush();
+ out.close();
+ }
+
+ public void targetStarted(BuildEvent event) {
+ log( ">> TARGET STARTED -- " + event.getTarget(), Project.MSG_DEBUG );
+ log( lSep + event.getTarget().getName() + ":", Project.MSG_INFO );
+ targetStartTime = System.currentTimeMillis();
+ }
+
+ public void targetFinished(BuildEvent event) {
+ log( "<< TARGET FINISHED -- " + event.getTarget(), Project.MSG_DEBUG );
+ String time = formatTime( System.currentTimeMillis() - targetStartTime );
+ log( event.getTarget() + ": duration " + time, Project.MSG_VERBOSE );
+ out.flush();
+ }
+
+ public void taskStarted(BuildEvent event) {
+ log( ">>> TAST STARTED -- " + event.getTask(), Project.MSG_DEBUG );
+ }
+
+ public void taskFinished(BuildEvent event) {
+ log( "<<< TASK FINISHED -- " + event.getTask(), Project.MSG_DEBUG );
+ out.flush();
+ }
+
+ public void messageLogged(BuildEvent event) {
+ log( "--- MESSAGE LOGGED", Project.MSG_DEBUG );
+
+ StringBuffer buf = new StringBuffer();
+ if ( event.getTask() != null ) {
+ String name = "[" + event.getTask().getTaskName() + "]";
+ /** @todo replace 12 with DefaultLogger.LEFT_COLUMN_SIZE */
+ for ( int i = 0; i < (12 - name.length()); i++ ) {
+ buf.append( " " );
+ } // for
+ buf.append( name );
+ } // if
+ buf.append( event.getMessage() );
+
+ log( buf.toString(), event.getPriority() );
+ }
+
+ /**
+ * The thing that actually sends the information to the output.
+ * @param mesg The message to log.
+ * @param level The verbosity level of the message.
+ */
+ private void log( String mesg, int level ) {
+ if ( record && (level <= loglevel) ) {
+ out.println(mesg);
+ }
+ }
+
+ public void setMessageOutputLevel(int level) {
+ if ( level >= Project.MSG_ERR && level <= Project.MSG_DEBUG )
+ loglevel = level;
+ }
+
+ public void setOutputPrintStream(PrintStream output) {
+ out = output;
+ }
+
+ public void setEmacsMode(boolean emacsMode) {
+ throw new java.lang.UnsupportedOperationException("Method setEmacsMode() not yet implemented.");
+ }
+
+ public void setErrorPrintStream(PrintStream err) {
+ out = err;
+ }
+
+ private static String formatTime(long millis) {
+ long seconds = millis / 1000;
+ long minutes = seconds / 60;
+
+
+ if (minutes > 0) {
+ return Long.toString(minutes) + " minute"
+ + (minutes == 1 ? " " : "s ")
+ + Long.toString(seconds%60) + " second"
+ + (seconds%60 == 1 ? "" : "s");
+ }
+ else {
+ return Long.toString(seconds) + " second"
+ + (seconds%60 == 1 ? "" : "s");
+ }
+
+ }
+}
diff --git a/src/main/org/apache/tools/ant/taskdefs/defaults.properties b/src/main/org/apache/tools/ant/taskdefs/defaults.properties
index 66ea759aa..db7569b10 100644
--- a/src/main/org/apache/tools/ant/taskdefs/defaults.properties
+++ b/src/main/org/apache/tools/ant/taskdefs/defaults.properties
@@ -43,6 +43,7 @@ fail=org.apache.tools.ant.taskdefs.Exit
war=org.apache.tools.ant.taskdefs.War
uptodate=org.apache.tools.ant.taskdefs.UpToDate
apply=org.apache.tools.ant.taskdefs.Transform
+recorder=org.apache.tools.ant.taskdefs.Recorder
# optional tasks
script=org.apache.tools.ant.taskdefs.optional.Script