- Moved the remaining System.out calls to the DefaultLogger - Cleaned up the default output - Added System.exit to main() tools can still invoke the runBuild method without an exit being called. - Changed javac task logging to stream out a line at a time Submitted by: Matt Foemmel <mpfoemme@ThoughtWorks.com> git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@267725 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -62,8 +62,11 @@ import java.io.*; | |||
| * any messages that get logged. | |||
| */ | |||
| public class DefaultLogger implements BuildListener { | |||
| private static int LEFT_COLUMN_SIZE = 12; | |||
| private PrintStream out; | |||
| private int msgOutputLevel; | |||
| private long startTime; | |||
| /** | |||
| * Constructs a new logger which will write to the specified | |||
| @@ -75,16 +78,47 @@ public class DefaultLogger implements BuildListener { | |||
| this.msgOutputLevel = msgOutputLevel; | |||
| } | |||
| public void buildStarted(BuildEvent event) {} | |||
| public void buildFinished(BuildEvent event) {} | |||
| public void buildStarted(BuildEvent event) { | |||
| startTime = System.currentTimeMillis(); | |||
| } | |||
| /** | |||
| * Prints whether the build succeeded or failed, and | |||
| * any errors the occured during the build. | |||
| */ | |||
| public void buildFinished(BuildEvent event) { | |||
| Throwable error = event.getException(); | |||
| if (error == null) { | |||
| out.println("\nBUILD SUCCESSFUL"); | |||
| } | |||
| else { | |||
| out.println("\nBUILD FAILED\n"); | |||
| if (error instanceof BuildException) { | |||
| out.println(error.toString()); | |||
| Throwable nested = ((BuildException)error).getException(); | |||
| if (nested != null) { | |||
| nested.printStackTrace(out); | |||
| } | |||
| } | |||
| else { | |||
| error.printStackTrace(out); | |||
| } | |||
| } | |||
| out.println("\nTotal time: " + formatTime(System.currentTimeMillis() - startTime)); | |||
| } | |||
| public void targetStarted(BuildEvent event) { | |||
| if (msgOutputLevel <= Project.MSG_INFO) { | |||
| out.println("Executing Target: " + event.getTarget().getName()); | |||
| out.println("\n" + event.getTarget().getName() + ":"); | |||
| } | |||
| } | |||
| public void targetFinished(BuildEvent event) {} | |||
| public void targetFinished(BuildEvent event) { | |||
| } | |||
| public void taskStarted(BuildEvent event) {} | |||
| public void taskFinished(BuildEvent event) {} | |||
| @@ -101,11 +135,31 @@ public class DefaultLogger implements BuildListener { | |||
| if (pos != -1) { | |||
| name = name.substring(pos + 1); | |||
| } | |||
| out.print("[" + name + "] "); | |||
| String msg = "[" + name + "] "; | |||
| for (int i = 0; i < (LEFT_COLUMN_SIZE - msg.length()); i++) { | |||
| out.print(" "); | |||
| } | |||
| out.print(msg); | |||
| } | |||
| // Print the message | |||
| out.println(event.getMessage()); | |||
| } | |||
| } | |||
| } | |||
| private static String formatTime(long millis) { | |||
| long seconds = millis / 1000; | |||
| long minutes = seconds / 60; | |||
| if (minutes > 0) { | |||
| return Long.toString(minutes) + " minutes " + Long.toString(seconds%60) + " seconds"; | |||
| } | |||
| else { | |||
| return Long.toString(seconds) + " seconds"; | |||
| } | |||
| } | |||
| } | |||
| @@ -103,7 +103,13 @@ public class Main { | |||
| * @param args Command line args. | |||
| */ | |||
| public static void main(String[] args) { | |||
| new Main(args).runBuild(); | |||
| try { | |||
| new Main(args).runBuild(); | |||
| System.exit(0); | |||
| } | |||
| catch(Throwable exc) { | |||
| System.exit(1); | |||
| } | |||
| } | |||
| protected Main(String[] args) throws BuildException { | |||
| @@ -194,7 +200,7 @@ public class Main { | |||
| // if it's no other arg, it may be the target | |||
| targets.addElement(arg); | |||
| } | |||
| } | |||
| // make sure buildfile exists | |||
| @@ -224,10 +230,9 @@ public class Main { | |||
| if (!readyToRun) { | |||
| return; | |||
| } | |||
| // track when we started | |||
| long startTime = System.currentTimeMillis(); | |||
| if (msgOutputLevel >= Project.MSG_INFO) { | |||
| System.out.println("Buildfile: " + buildFile); | |||
| } | |||
| @@ -235,21 +240,24 @@ public class Main { | |||
| Project project = new Project(); | |||
| addBuildListeners(project); | |||
| project.fireBuildStarted(); | |||
| project.init(); | |||
| // set user-define properties | |||
| Enumeration e = definedProps.keys(); | |||
| while (e.hasMoreElements()) { | |||
| String arg = (String)e.nextElement(); | |||
| String value = (String)definedProps.get(arg); | |||
| project.setUserProperty(arg, value); | |||
| } | |||
| project.setUserProperty( "ant.file" , buildFile.getAbsolutePath() ); | |||
| Throwable error = null; | |||
| // first use the ProjectHelper to create the project object | |||
| // from the given build file. | |||
| try { | |||
| project.init(); | |||
| // set user-define properties | |||
| Enumeration e = definedProps.keys(); | |||
| while (e.hasMoreElements()) { | |||
| String arg = (String)e.nextElement(); | |||
| String value = (String)definedProps.get(arg); | |||
| project.setUserProperty(arg, value); | |||
| } | |||
| project.setUserProperty( "ant.file" , buildFile.getAbsolutePath() ); | |||
| // first use the ProjectHelper to create the project object | |||
| // from the given build file. | |||
| try { | |||
| Class.forName("javax.xml.parsers.SAXParserFactory"); | |||
| ProjectHelper.configureProject(project, buildFile); | |||
| @@ -260,40 +268,25 @@ public class Main { | |||
| } catch (NullPointerException npe) { | |||
| throw new BuildException("No JAXP compliant XML parser found. See http://java.sun.com/xml for the\nreference implementation.", npe); | |||
| } | |||
| } catch (BuildException be) { | |||
| System.out.println("\nBUILD CONFIG ERROR\n"); | |||
| System.out.println(be.getMessage()); | |||
| if (be.getException() == null) { | |||
| System.out.println(be.toString()); | |||
| } else { | |||
| be.getException().printStackTrace(); | |||
| } | |||
| throw be; | |||
| } | |||
| // make sure that we have a target to execute | |||
| if (targets.size() == 0) { | |||
| targets.addElement(project.getDefaultTarget()); | |||
| } | |||
| // make sure that we have a target to execute | |||
| if (targets.size() == 0) { | |||
| targets.addElement(project.getDefaultTarget()); | |||
| } | |||
| // actually do some work | |||
| try { | |||
| // actually do some work | |||
| project.executeTargets(targets); | |||
| } catch (BuildException be) { | |||
| String msg = "\nBUILD FATAL ERROR\n\n"; | |||
| System.out.println(msg + be.toString()); | |||
| if (msgOutputLevel > Project.MSG_INFO) { | |||
| be.printStackTrace(); | |||
| } | |||
| throw be; | |||
| } | |||
| // track our stop time and let the user know how long things took. | |||
| long finishTime = System.currentTimeMillis(); | |||
| long elapsedTime = finishTime - startTime; | |||
| if (msgOutputLevel >= Project.MSG_INFO) { | |||
| System.out.println("Completed in " + (elapsedTime/1000) | |||
| + " seconds"); | |||
| catch(RuntimeException exc) { | |||
| error = exc; | |||
| throw exc; | |||
| } | |||
| catch(Error err) { | |||
| error = err; | |||
| throw err; | |||
| } | |||
| finally { | |||
| project.fireBuildFinished(error); | |||
| } | |||
| } | |||
| @@ -344,11 +337,11 @@ public class Main { | |||
| private static void printVersion() { | |||
| try { | |||
| Properties props = new Properties(); | |||
| InputStream in = | |||
| InputStream in = | |||
| Main.class.getResourceAsStream("/org/apache/tools/ant/version.txt"); | |||
| props.load(in); | |||
| in.close(); | |||
| String lSep = System.getProperty("line.separator"); | |||
| StringBuffer msg = new StringBuffer(); | |||
| msg.append("Ant version "); | |||
| @@ -261,7 +261,7 @@ public class Project { | |||
| this.baseDir = baseDir; | |||
| setProperty( "basedir", baseDir.getAbsolutePath()); | |||
| String msg = "Project base dir set to: " + baseDir; | |||
| log(msg, MSG_INFO); | |||
| log(msg, MSG_VERBOSE); | |||
| } | |||
| public File getBaseDir() { | |||
| @@ -407,17 +407,8 @@ public class Project { | |||
| public void executeTargets(Vector targetNames) throws BuildException { | |||
| Throwable error = null; | |||
| try { | |||
| for (int i = 0; i < targetNames.size(); i++) { | |||
| executeTarget((String)targetNames.elementAt(i)); | |||
| } | |||
| } | |||
| catch(RuntimeException exc) { | |||
| error = exc; | |||
| throw exc; | |||
| } | |||
| finally { | |||
| fireBuildFinished(error); | |||
| for (int i = 0; i < targetNames.size(); i++) { | |||
| executeTarget((String)targetNames.elementAt(i)); | |||
| } | |||
| } | |||
| @@ -0,0 +1,118 @@ | |||
| /* | |||
| * The Apache Software License, Version 1.1 | |||
| * | |||
| * Copyright (c) 1999 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", "Tomcat", 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 | |||
| * <http://www.apache.org/>. | |||
| * | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import org.apache.tools.ant.*; | |||
| import java.io.*; | |||
| /** | |||
| * Redirects text written to a stream thru the standard | |||
| * ant logging mechanism. This class is useful for integrating | |||
| * with tools that write to System.out and System.err. For example, | |||
| * the following will cause all text written to System.out to be | |||
| * logged with "info" priority: | |||
| * <pre>System.setOut(new PrintStream(new TaskOutputStream(project, Project.MSG_INFO)));</pre> | |||
| * | |||
| * @author James Duncan Davidson (duncan@x180.com) | |||
| */ | |||
| public class TaskOutputStream extends OutputStream { | |||
| private Project project; | |||
| private StringBuffer line; | |||
| private int msgOutputLevel; | |||
| /** | |||
| * Constructs a new JavacOutputStream with the given project | |||
| * as the output source for messages. | |||
| */ | |||
| TaskOutputStream(Project project, int msgOutputLevel) { | |||
| this.project = project; | |||
| this.msgOutputLevel = msgOutputLevel; | |||
| line = new StringBuffer(); | |||
| } | |||
| /** | |||
| * Write a character to the output stream. This method looks | |||
| * to make sure that there isn't an error being reported and | |||
| * will flush each line of input out to the project's log stream. | |||
| */ | |||
| public void write(int c) throws IOException { | |||
| char cc = (char)c; | |||
| if (cc == '\r' || cc == '\n') { | |||
| // line feed | |||
| if (line.length() > 0) { | |||
| processLine(); | |||
| } | |||
| } else { | |||
| line.append(cc); | |||
| } | |||
| } | |||
| /** | |||
| * Processes a line of input and determines if an error occured. | |||
| */ | |||
| private void processLine() { | |||
| String s = line.toString(); | |||
| project.log(s, msgOutputLevel); | |||
| line = new StringBuffer(); | |||
| } | |||
| } | |||
| @@ -92,7 +92,7 @@ public class Javac extends MatchingTask { | |||
| * Integer returned by the "Modern" jdk1.3 compiler to indicate success. | |||
| */ | |||
| private static final int | |||
| MODERN_COMPILER_SUCCESS = 0; | |||
| MODERN_COMPILER_SUCCESS = 0; | |||
| private File srcDir; | |||
| private File destDir; | |||
| @@ -237,10 +237,10 @@ public class Javac extends MatchingTask { | |||
| // copy the support files | |||
| if (filecopyList.size() > 0) { | |||
| project.log("The implicit copying of support files by javac has been deprecated. " + | |||
| project.log("The implicit copying of support files by javac has been deprecated. " + | |||
| "Use the copydir task to copy support files explicitly.", | |||
| Project.MSG_WARN); | |||
| project.log("Copying " + filecopyList.size() + | |||
| " support files to " + destDir.getAbsolutePath()); | |||
| Enumeration enum = filecopyList.keys(); | |||
| @@ -427,17 +427,10 @@ public class Javac extends MatchingTask { | |||
| // provide the compiler a different message sink - namely our own | |||
| ByteArrayOutputStream out = new ByteArrayOutputStream(); | |||
| sun.tools.javac.Main compiler = new sun.tools.javac.Main(out, "javac"); | |||
| if (compiler.compile(args)) { | |||
| String output = out.toString().trim(); | |||
| if (output.length() > 0) { | |||
| project.log(output, Project.MSG_WARN); | |||
| } | |||
| } | |||
| else { | |||
| project.log(out.toString().trim(), Project.MSG_ERR); | |||
| sun.tools.javac.Main compiler = | |||
| new sun.tools.javac.Main(new TaskOutputStream(project, Project.MSG_WARN), "javac"); | |||
| if (!compiler.compile(args)) { | |||
| throw new BuildException("Compile failed"); | |||
| } | |||
| } | |||
| @@ -505,28 +498,27 @@ public class Javac extends MatchingTask { | |||
| project.log(niceSourceList.toString(), project.MSG_VERBOSE); | |||
| // This won't build under JDK1.2.2 because the new compiler | |||
| // doesn't exist there. | |||
| // This won't build under JDK1.2.2 because the new compiler | |||
| // doesn't exist there. | |||
| //com.sun.tools.javac.Main compiler = new com.sun.tools.javac.Main(); | |||
| //if (compiler.compile(args) != 0) { | |||
| // Use reflection to be able to build on all JDKs >= 1.1: | |||
| try { | |||
| Class c = Class.forName ("com.sun.tools.javac.Main"); | |||
| Object compiler = c.newInstance (); | |||
| Method compile = c.getMethod ("compile", | |||
| new Class [] {(new String [] {}).getClass ()}); | |||
| int result = ((Integer) compile.invoke | |||
| (compiler, new Object [] {args})) .intValue (); | |||
| if (result != MODERN_COMPILER_SUCCESS) { | |||
| String msg = | |||
| "Compile failed, messages should have been provided."; | |||
| throw new BuildException(msg); | |||
| } | |||
| } catch (Exception ex) { | |||
| throw new BuildException (ex); | |||
| // Use reflection to be able to build on all JDKs >= 1.1: | |||
| try { | |||
| Class c = Class.forName ("com.sun.tools.javac.Main"); | |||
| Object compiler = c.newInstance (); | |||
| Method compile = c.getMethod ("compile", | |||
| new Class [] {(new String [] {}).getClass ()}); | |||
| int result = ((Integer) compile.invoke | |||
| (compiler, new Object [] {args})) .intValue (); | |||
| if (result != MODERN_COMPILER_SUCCESS) { | |||
| String msg = | |||
| "Compile failed, messages should have been provided."; | |||
| throw new BuildException(msg); | |||
| } | |||
| } catch (Exception ex) { | |||
| throw new BuildException (ex); | |||
| } | |||
| } | |||
| /** | |||