diff --git a/WHATSNEW b/WHATSNEW index a542e16f9..f88245a2b 100644 --- a/WHATSNEW +++ b/WHATSNEW @@ -148,6 +148,8 @@ Other changes: nested element as nested text instead of using the 'value' attribute. +* A new logger, BigProjectLogger, lists the project name with every target + Changes from Ant 1.6.5 to Ant 1.7.0 =================================== diff --git a/docs/manual/listeners.html b/docs/manual/listeners.html index 756cb53b6..36bd7e99c 100644 --- a/docs/manual/listeners.html +++ b/docs/manual/listeners.html @@ -44,13 +44,19 @@ listeners and loggers.

  • message logged
  • +

    + These are used internally for various recording and housekeeping operations, + however new listeners may registered on the command line through the -listener + argument. +

    +

    Loggers

    Loggers extend the capabilities of listeners and add the following features:

    @@ -104,7 +110,11 @@ listeners and loggers.

    Prints the time that a build finished BuildLogger - + + org.apache.tools.ant.BigProjectLogger + Prints the project name every target + BuildLogger +

    DefaultLogger

    @@ -235,7 +245,7 @@ in the console using applications like cat, more, etc.

    color codes. It works on XTerm, ETerm, Win9x Console (with ANSI.SYS loaded.), etc.

    NOTE: -It doesn't work on WinNT even when a COMMAND.COM console loaded with +It doesn't work on WinNT and successors, even when a COMMAND.COM console loaded with ANSI.SYS is used.

    If the user wishes to override the default colors with custom ones, a file containing zero or more of the @@ -318,7 +328,7 @@ corresponding Log4j level.

    -

    To use Log4j you will need the Log4j jar file and a 'log4j.properties' +

    To use Log4j you will need the Log4j JAR file and a 'log4j.properties' configuration file. Both should be placed somewhere in your Ant classpath. If the log4j.properties is in your project root folder you can add this with -lib option:

    @@ -386,6 +396,7 @@ is declared at all.
       BUILD SUCCESSFUL - at 16/08/05 16:24
     
    +

    To use this listener, use the command:

    @@ -393,6 +404,63 @@ is declared at all.
    +

    BigProjectLogger

    + +

    + This logger is designed to make examining the logs of a big build easier, + especially those run under continuous integration tools. It +

    +
      +
    1. When entering a child project, prints its name and directory
    2. +
    3. When exiting a child project, prints its name
    4. +
    5. Includes the name of the project when printing a target
    6. +
    7. Omits logging the names of all targets that have no direct task output
    8. +
    9. Includes the build finished timestamp of the TimeStamp logger
    10. +
    +

    + This is useful when using <subant> to build a large project + from many smaller projects -the output shows which particular + project is building. Here is an example in which "clean" is being called + on all a number of child projects, only some of which perform work: +

    +
    +
    +======================================================================
    +Entering project "xunit"
    +In /home/ant/components/xunit
    +======================================================================
    +
    +xunit.clean:
    +   [delete] Deleting directory /home/ant/components/xunit/build
    +   [delete] Deleting directory /home/ant/components/xunit/dist
    +
    +======================================================================
    +Exiting project "xunit"
    +======================================================================
    +
    +======================================================================
    +Entering project "junit"
    +In /home/ant/components/junit
    +======================================================================
    +
    +======================================================================
    +Exiting project "junit"
    +======================================================================
    +
    + +

    + The entry and exit messages are very verbose in this example, but in + a big project compiling or testing many child components, the messages + are reduced to becoming clear delimiters of where different projects + are in charge -or more importantly, which project is failing. +

    + +

    To use this listener, use the command:

    +
    + +ant -logger org.apache.tools.ant.listener.BigProjectLogger + +

    Writing your own

    @@ -402,8 +470,25 @@ developers.

    Notes:

    diff --git a/src/main/org/apache/tools/ant/DefaultLogger.java b/src/main/org/apache/tools/ant/DefaultLogger.java index f2cc6ca72..1debc8874 100644 --- a/src/main/org/apache/tools/ant/DefaultLogger.java +++ b/src/main/org/apache/tools/ant/DefaultLogger.java @@ -22,9 +22,12 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.PrintStream; import java.io.StringReader; +import java.util.Date; +import java.text.DateFormat; import org.apache.tools.ant.util.DateUtils; import org.apache.tools.ant.util.StringUtils; +import org.apache.tools.ant.util.FileUtils; /** * Writes build events to a PrintStream. Currently, it @@ -251,9 +254,9 @@ public class DefaultLogger implements BuildLogger { tmp.append(label); label = tmp.toString(); + BufferedReader r = null; try { - BufferedReader r = - new BufferedReader( + r = new BufferedReader( new StringReader(event.getMessage())); String line = r.readLine(); boolean first = true; @@ -273,8 +276,14 @@ public class DefaultLogger implements BuildLogger { } catch (IOException e) { // shouldn't be possible message.append(label).append(event.getMessage()); + } finally { + if (r != null) { + FileUtils.close(r); + } } + } else { + //emacs mode or there is no task message.append(event.getMessage()); } Throwable ex = event.getException(); @@ -329,4 +338,27 @@ public class DefaultLogger implements BuildLogger { */ protected void log(String message) { } + + /** + * Get the current time. + * @return the current time as a formatted string. + * @since Ant1.7.1 + */ + protected String getTimestamp() { + Date date = new Date(System.currentTimeMillis()); + DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT); + String finishTime = formatter.format(date); + return finishTime; + } + + /** + * Get the project name or null + * @param event the event + * @return the project that raised this event + * @since Ant1.7.1 + */ + protected String extractProjectName(BuildEvent event) { + Project project = event.getProject(); + return project!=null?project.getName():null; + } } diff --git a/src/main/org/apache/tools/ant/NoBannerLogger.java b/src/main/org/apache/tools/ant/NoBannerLogger.java index 75b8f7129..956e3c58c 100644 --- a/src/main/org/apache/tools/ant/NoBannerLogger.java +++ b/src/main/org/apache/tools/ant/NoBannerLogger.java @@ -49,7 +49,17 @@ public class NoBannerLogger extends DefaultLogger { * Must not be null. */ public void targetStarted(BuildEvent event) { - targetName = event.getTarget().getName(); + targetName = extractTargetName(event); + } + + /** + * Override point, extract the target name + * @param event the event to work on + * @return the target name to print + * @since Ant1.7.1 + */ + protected String extractTargetName(BuildEvent event) { + return event.getTarget().getName(); } /** diff --git a/src/main/org/apache/tools/ant/listener/AnsiColorLogger.java b/src/main/org/apache/tools/ant/listener/AnsiColorLogger.java index b01317b17..39c96cce3 100644 --- a/src/main/org/apache/tools/ant/listener/AnsiColorLogger.java +++ b/src/main/org/apache/tools/ant/listener/AnsiColorLogger.java @@ -96,7 +96,7 @@ import org.apache.tools.ant.Project; * 47 -> White * */ -public final class AnsiColorLogger extends DefaultLogger { +public class AnsiColorLogger extends DefaultLogger { // private static final int ATTR_NORMAL = 0; // private static final int ATTR_BRIGHT = 1; private static final int ATTR_DIM = 2; diff --git a/src/main/org/apache/tools/ant/listener/BigProjectLogger.java b/src/main/org/apache/tools/ant/listener/BigProjectLogger.java new file mode 100644 index 000000000..c7d45c232 --- /dev/null +++ b/src/main/org/apache/tools/ant/listener/BigProjectLogger.java @@ -0,0 +1,171 @@ +/* + * Copyright 2007 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.listener; + +import org.apache.tools.ant.BuildEvent; +import org.apache.tools.ant.NoBannerLogger; +import org.apache.tools.ant.SubBuildListener; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.util.StringUtils; + +import java.io.File; + +/** + * This is a special logger that is designed to make it easier to work with big projects, those that use imports and + * subant to build complex systems. + * + * @since Ant1.7.1 + */ + +public class BigProjectLogger extends NoBannerLogger implements SubBuildListener { + + /** + * Header string for the log. + * {@value} + */ + public static final String HEADER="======================================================================"; + /** + * Footer string for the log. + * {@value} + */ + public static final String FOOTER=HEADER; + + /** + * This is an override point: the message that indicates whether a build failed. Subclasses can change/enhance the + * message. + * + * @return The classic "BUILD FAILED" plus a timestamp + */ + protected String getBuildFailedMessage() { + return super.getBuildFailedMessage() + TimestampedLogger.SPACER + getTimestamp(); + } + + /** + * This is an override point: the message that indicates that a build succeeded. Subclasses can change/enhance the + * message. + * + * @return The classic "BUILD SUCCESSFUL" plus a timestamp + */ + protected String getBuildSuccessfulMessage() { + return super.getBuildSuccessfulMessage() + TimestampedLogger.SPACER + getTimestamp(); + } + + + /** + * {@inheritDoc} + * + * @param event + */ + public void buildStarted(BuildEvent event) { + super.buildStarted(event); + subBuildStarted(event); + } + + /** + * {@inheritDoc} + * + * @param event + */ + public void buildFinished(BuildEvent event) { + subBuildFinished(event); + super.buildFinished(event); + } + + /** + * Override point, extract the target name + * + * @param event the event to work on + * @return the target name -including the owning project name (if non-null) + */ + protected String extractTargetName(BuildEvent event) { + String targetName = event.getTarget().getName(); + String projectName = extractProjectName(event); + if (projectName != null && targetName != null) { + return projectName + '.' + targetName; + } else { + return targetName; + } + } + + + /** + * {@inheritDoc} + * + * @param event An event with any relevant extra information. Must not be null. + */ + public void subBuildStarted(BuildEvent event) { + String name = extractNameOrDefault(event); + Project project = event.getProject(); + + File base = project == null ? null : project.getBaseDir(); + String path = base == null ? + "With no base directory" + : "In " + base.getAbsolutePath(); + printMessage(StringUtils.LINE_SEP + getHeader() + + StringUtils.LINE_SEP +"Entering project " + name + + StringUtils.LINE_SEP + path + +StringUtils.LINE_SEP + getFooter(), + out, + event.getPriority()); + } + + /** + * Get the name of an event + * + * @param event the event name + * @return the name or a default string + */ + protected String extractNameOrDefault(BuildEvent event) { + String name = extractProjectName(event); + if (name == null) { + name = ""; + } else { + name = '"'+name+'"'; + } + return name; + } + + /** {@inheritDoc} */ + public void subBuildFinished(BuildEvent event) { + String name = extractNameOrDefault(event); + String failed = event.getException() != null ? "failing " : ""; + printMessage(StringUtils.LINE_SEP + getHeader() + + StringUtils.LINE_SEP + "Exiting " + failed + "project " + + name + + StringUtils.LINE_SEP + getFooter(), + out, + event.getPriority()); + } + + /** + * Override point: return the header string for the entry/exit message + * @return the header string + */ + protected String getHeader() { + return HEADER; + } + + /** + * Override point: return the footer string for the entry/exit message + * @return the footer string + */ + protected String getFooter() { + return FOOTER; + } + +} diff --git a/src/main/org/apache/tools/ant/listener/TimestampedLogger.java b/src/main/org/apache/tools/ant/listener/TimestampedLogger.java index 33a932a61..eab9a41a5 100644 --- a/src/main/org/apache/tools/ant/listener/TimestampedLogger.java +++ b/src/main/org/apache/tools/ant/listener/TimestampedLogger.java @@ -31,14 +31,14 @@ public class TimestampedLogger extends DefaultLogger { /** * what appears between the old message and the new */ - private static final String SPACER = " - at "; + public static final String SPACER = " - at "; /** * This is an override point: the message that indicates whether a build failed. * Subclasses can change/enhance the message. * - * @return The classic "BUILD FAILED" + * @return The classic "BUILD FAILED" plus a timestamp */ protected String getBuildFailedMessage() { return super.getBuildFailedMessage() + SPACER + getTimestamp(); @@ -48,20 +48,10 @@ public class TimestampedLogger extends DefaultLogger { * This is an override point: the message that indicates that a build succeeded. * Subclasses can change/enhance the message. * - * @return The classic "BUILD SUCCESSFUL" + * @return The classic "BUILD SUCCESSFUL" plus a timestamp */ protected String getBuildSuccessfulMessage() { return super.getBuildSuccessfulMessage() + SPACER + getTimestamp(); } - /** - * Get the current time. - * @return the current time as a formatted string. - */ - protected String getTimestamp() { - Date date = new Date(System.currentTimeMillis()); - DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT); - String finishTime = formatter.format(date); - return finishTime; - } }