* Was not exiting with non-zero exit code when the build failed. * Fix the error reporting so that the entire exception chain is reported. * Only print out stack traces when in verbose or debug mode. * Wrap all exceptions thrown during task initialisation and execution with a general 'task failed' exception. * Another <property> testcase. git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@271802 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -41,4 +41,13 @@ | |||
| <property-test-type value="value 2"/> | |||
| </property> | |||
| </target> | |||
| <!-- Test setting the value more than once --> | |||
| <target name="too-many-values3"> | |||
| <property name="some-prop"> | |||
| <property-test-type value="value 1"/> | |||
| <property-test-type value="value 2"/> | |||
| <property-test-type value="value 3"/> | |||
| </property> | |||
| </target> | |||
| </project> | |||
| @@ -75,30 +75,41 @@ public class AspectAwareExecutor | |||
| final ExecutionFrame frame ) | |||
| throws TaskException | |||
| { | |||
| Configuration taskModel = getAspectManager().preCreate( model ); | |||
| taskModel = prepareAspects( taskModel ); | |||
| final String taskName = taskModel.getName(); | |||
| debug( "creating.notice", taskName ); | |||
| final Task task = createTask( taskName, frame ); | |||
| getAspectManager().postCreate( task ); | |||
| debug( "logger.notice", taskName ); | |||
| final Logger logger = frame.getLogger(); | |||
| getAspectManager().preLogEnabled( logger ); | |||
| doLogEnabled( task, taskModel, logger ); | |||
| debug( "contextualizing.notice", taskName ); | |||
| doContextualize( task, taskModel, frame.getContext() ); | |||
| debug( "configuring.notice", taskName ); | |||
| getAspectManager().preConfigure( taskModel ); | |||
| doConfigure( task, taskModel, frame.getContext() ); | |||
| debug( "executing.notice", taskName ); | |||
| getAspectManager().preExecute(); | |||
| doExecute( taskModel, task ); | |||
| getAspectManager().preDestroy(); | |||
| try | |||
| { | |||
| Configuration taskModel = getAspectManager().preCreate( model ); | |||
| taskModel = prepareAspects( taskModel ); | |||
| final String taskName = taskModel.getName(); | |||
| debug( "creating.notice", taskName ); | |||
| final Task task = doCreateTask( taskName, frame ); | |||
| getAspectManager().postCreate( task ); | |||
| debug( "logger.notice", taskName ); | |||
| final Logger logger = frame.getLogger(); | |||
| getAspectManager().preLogEnabled( logger ); | |||
| doLogEnabled( task, taskModel, logger ); | |||
| debug( "contextualizing.notice", taskName ); | |||
| doContextualize( task, taskModel, frame.getContext() ); | |||
| debug( "configuring.notice", taskName ); | |||
| getAspectManager().preConfigure( taskModel ); | |||
| doConfigure( task, taskModel, frame.getContext() ); | |||
| debug( "executing.notice", taskName ); | |||
| getAspectManager().preExecute(); | |||
| doExecute( taskModel, task ); | |||
| getAspectManager().preDestroy(); | |||
| } | |||
| catch( Exception e ) | |||
| { | |||
| // Wrap in generic error message | |||
| final String message = REZ.getString( "execute.error", | |||
| model.getName(), | |||
| model.getLocation() ); | |||
| throw new TaskException( message, e ); | |||
| } | |||
| } | |||
| protected void doExecute( final Configuration taskModel, final Task task ) | |||
| @@ -10,6 +10,7 @@ package org.apache.myrmidon.components.executor; | |||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
| import org.apache.avalon.excalibur.i18n.Resources; | |||
| import org.apache.avalon.framework.configuration.Configuration; | |||
| import org.apache.avalon.framework.configuration.ConfigurationException; | |||
| import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||
| import org.apache.avalon.framework.logger.LogEnabled; | |||
| import org.apache.avalon.framework.logger.Logger; | |||
| @@ -52,24 +53,36 @@ public class DefaultExecutor | |||
| m_configurer = (Configurer)serviceManager.lookup( Configurer.ROLE ); | |||
| } | |||
| /** | |||
| * Executes a task. | |||
| */ | |||
| public void execute( final Configuration taskModel, final ExecutionFrame frame ) | |||
| throws TaskException | |||
| { | |||
| final String taskName = taskModel.getName(); | |||
| debug( "creating.notice", taskName ); | |||
| final Task task = createTask( taskName, frame ); | |||
| try | |||
| { | |||
| debug( "creating.notice", taskName ); | |||
| final Task task = doCreateTask( taskName, frame ); | |||
| debug( "logger.notice", taskName ); | |||
| doLogEnabled( task, taskModel, frame.getLogger() ); | |||
| debug( "logger.notice", taskName ); | |||
| doLogEnabled( task, taskModel, frame.getLogger() ); | |||
| debug( "contextualizing.notice", taskName ); | |||
| doContextualize( task, taskModel, frame.getContext() ); | |||
| debug( "contextualizing.notice", taskName ); | |||
| doContextualize( task, taskModel, frame.getContext() ); | |||
| debug( "configuring.notice", taskName ); | |||
| doConfigure( task, taskModel, frame.getContext() ); | |||
| debug( "configuring.notice", taskName ); | |||
| doConfigure( task, taskModel, frame.getContext() ); | |||
| debug( "executing.notice", taskName ); | |||
| task.execute(); | |||
| debug( "executing.notice", taskName ); | |||
| task.execute(); | |||
| } | |||
| catch( Exception e ) | |||
| { | |||
| // Wrap in generic error message | |||
| final String message = REZ.getString( "execute.error", taskName, taskModel.getLocation() ); | |||
| throw new TaskException( message, e ); | |||
| } | |||
| } | |||
| protected final void debug( final String key, final String taskName ) | |||
| @@ -84,7 +97,7 @@ public class DefaultExecutor | |||
| /** | |||
| * Creates a task instance. | |||
| */ | |||
| protected final Task createTask( final String name, final ExecutionFrame frame ) | |||
| protected final Task doCreateTask( final String name, final ExecutionFrame frame ) | |||
| throws TaskException | |||
| { | |||
| try | |||
| @@ -94,7 +107,7 @@ public class DefaultExecutor | |||
| } | |||
| catch( final TypeException te ) | |||
| { | |||
| final String message = REZ.getString( "no-create.error", name ); | |||
| final String message = REZ.getString( "create.error", name ); | |||
| throw new TaskException( message, te ); | |||
| } | |||
| } | |||
| @@ -105,20 +118,9 @@ public class DefaultExecutor | |||
| protected final void doConfigure( final Task task, | |||
| final Configuration taskModel, | |||
| final TaskContext taskContext ) | |||
| throws TaskException | |||
| throws ConfigurationException | |||
| { | |||
| try | |||
| { | |||
| m_configurer.configure( task, taskModel, taskContext ); | |||
| } | |||
| catch( final Throwable throwable ) | |||
| { | |||
| final String message = | |||
| REZ.getString( "config.error", | |||
| taskModel.getName(), | |||
| taskModel.getLocation() ); | |||
| throw new TaskException( message, throwable ); | |||
| } | |||
| m_configurer.configure( task, taskModel, taskContext ); | |||
| } | |||
| /** | |||
| @@ -136,9 +138,7 @@ public class DefaultExecutor | |||
| catch( final Throwable throwable ) | |||
| { | |||
| final String message = | |||
| REZ.getString( "contextualize.error", | |||
| taskModel.getName(), | |||
| taskModel.getLocation() ); | |||
| REZ.getString( "contextualize.error", taskModel.getName() ); | |||
| throw new TaskException( message, throwable ); | |||
| } | |||
| } | |||
| @@ -160,9 +160,7 @@ public class DefaultExecutor | |||
| catch( final Throwable throwable ) | |||
| { | |||
| final String message = | |||
| REZ.getString( "logger.error", | |||
| taskModel.getName(), | |||
| taskModel.getLocation() ); | |||
| REZ.getString( "logger.error", taskModel.getName() ); | |||
| throw new TaskException( message, throwable ); | |||
| } | |||
| } | |||
| @@ -4,10 +4,10 @@ contextualizing.notice=Contextualizing {0}. | |||
| configuring.notice=Configuring {0}. | |||
| executing.notice=Executing {0}. | |||
| no-create.error=Could not create task "{0}". | |||
| config.error={1}: Could not configure task "{0}". | |||
| contextualize.error={1}: Could not set the context for task "{0}". | |||
| logger.error={1}: Could not set the logger for task "{0}". | |||
| create.error=Could not create task <{0}>. | |||
| contextualize.error=Could not set the context for task <{0}>. | |||
| logger.error=Could not set the logger for task <{0}>. | |||
| execute.error={1}: Could not execute task <{0}>. | |||
| unused-settings.error=Unused aspect settings for namespace {0} (parameterCount={1} elementCount={2}). | |||
| dispatch-settings.notice=Dispatching Aspect Settings to namespace {0} (parameterCount={1} elementCount={2}). | |||
| @@ -18,6 +18,7 @@ import org.apache.avalon.excalibur.cli.CLOptionDescriptor; | |||
| import org.apache.avalon.excalibur.cli.CLUtil; | |||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
| import org.apache.avalon.excalibur.i18n.Resources; | |||
| import org.apache.avalon.framework.CascadingException; | |||
| import org.apache.avalon.framework.ExceptionUtil; | |||
| import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||
| import org.apache.avalon.framework.logger.LogKitLogger; | |||
| @@ -105,6 +106,9 @@ public class CLIMain | |||
| ///Determine whether tasks are actually executed | |||
| private boolean m_dryRun = false; | |||
| ///Log level to use | |||
| private static Priority m_priority = Priority.WARN; | |||
| /** | |||
| * Main entry point called to run standard Myrmidon. | |||
| * | |||
| @@ -120,9 +124,7 @@ public class CLIMain | |||
| } | |||
| catch( final Throwable throwable ) | |||
| { | |||
| final String message = | |||
| REZ.getString( "error-message", ExceptionUtil.printStackTrace( throwable ) ); | |||
| System.err.println( message ); | |||
| main.reportError( throwable ); | |||
| exitCode = -1; | |||
| } | |||
| finally | |||
| @@ -219,6 +221,7 @@ public class CLIMain | |||
| } | |||
| private boolean parseCommandLineOptions( final String[] args ) | |||
| throws Exception | |||
| { | |||
| final CLOptionDescriptor[] options = createCLOptions(); | |||
| final CLArgsParser parser = new CLArgsParser( args, options ); | |||
| @@ -226,8 +229,7 @@ public class CLIMain | |||
| if( null != parser.getErrorString() ) | |||
| { | |||
| final String message = REZ.getString( "error-message", parser.getErrorString() ); | |||
| System.err.println( message ); | |||
| return false; | |||
| throw new Exception( message ); | |||
| } | |||
| final List clOptions = parser.getArguments(); | |||
| @@ -254,13 +256,13 @@ public class CLIMain | |||
| break; | |||
| case LOG_LEVEL_OPT: | |||
| m_parameters.setParameter( "log.level", option.getArgument() ); | |||
| m_priority = mapLogLevel( option.getArgument() ); | |||
| break; | |||
| case VERBOSE_OPT: | |||
| m_parameters.setParameter( "log.level", "INFO" ); | |||
| m_priority = Priority.INFO; | |||
| break; | |||
| case QUIET_OPT: | |||
| m_parameters.setParameter( "log.level", "ERROR" ); | |||
| m_priority = Priority.ERROR; | |||
| break; | |||
| case INCREMENTAL_OPT: | |||
| @@ -322,7 +324,7 @@ public class CLIMain | |||
| prepareLogging(); | |||
| final File homeDir = getHomeDir(); | |||
| checkHomeDir(); | |||
| final File buildFile = getBuildFile(); | |||
| //getLogger().debug( "Ant Bin Directory: " + m_binDir ); | |||
| @@ -336,24 +338,35 @@ public class CLIMain | |||
| } | |||
| final Embeddor embeddor = prepareEmbeddor(); | |||
| final ProjectListener listener = prepareListener( embeddor ); | |||
| //create the project | |||
| final Project project = | |||
| embeddor.createProject( buildFile.toString(), null, m_builderParameters ); | |||
| try | |||
| { | |||
| final ProjectListener listener = prepareListener( embeddor ); | |||
| //loop over build if we are in incremental mode.. | |||
| final boolean incremental = m_parameters.getParameterAsBoolean( "incremental", false ); | |||
| if( !incremental ) | |||
| //create the project | |||
| final Project project = | |||
| embeddor.createProject( buildFile.toString(), null, m_builderParameters ); | |||
| //loop over build if we are in incremental mode.. | |||
| final boolean incremental = m_parameters.getParameterAsBoolean( "incremental", false ); | |||
| if( !incremental ) | |||
| { | |||
| executeBuild( embeddor, project, listener ); | |||
| } | |||
| else | |||
| { | |||
| executeIncrementalBuild( embeddor, project, listener ); | |||
| } | |||
| } | |||
| catch( final Exception e ) | |||
| { | |||
| executeBuild( embeddor, project, listener ); | |||
| final String message = REZ.getString( "build-failed.error" ); | |||
| throw new CascadingException( message, e ); | |||
| } | |||
| else | |||
| finally | |||
| { | |||
| executeIncrementalBuild( embeddor, project, listener ); | |||
| shutdownEmbeddor( embeddor ); | |||
| } | |||
| shutdownEmbeddor( embeddor ); | |||
| } | |||
| private void executeIncrementalBuild( final Embeddor embeddor, | |||
| @@ -365,7 +378,14 @@ public class CLIMain | |||
| while( true ) | |||
| { | |||
| executeBuild( embeddor, project, listener ); | |||
| try | |||
| { | |||
| executeBuild( embeddor, project, listener ); | |||
| } | |||
| catch( final TaskException te ) | |||
| { | |||
| reportError( te ); | |||
| } | |||
| final String message = REZ.getString( "repeat.notice" ); | |||
| System.out.println( message ); | |||
| @@ -385,6 +405,44 @@ public class CLIMain | |||
| } | |||
| } | |||
| /** | |||
| * Builds the error message for an exception | |||
| */ | |||
| private void reportError( final Throwable throwable ) | |||
| { | |||
| // Build the message | |||
| final String message; | |||
| if( m_priority.isLowerOrEqual( Priority.INFO ) ) | |||
| { | |||
| // Verbose mode - include the stack traces | |||
| message = ExceptionUtil.printStackTrace( throwable, 5, true, true ); | |||
| } | |||
| else | |||
| { | |||
| // Build the message | |||
| final StringBuffer buffer = new StringBuffer(); | |||
| buffer.append( throwable.getMessage() ); | |||
| for( Throwable current = ExceptionUtil.getCause( throwable, true ); | |||
| current != null; | |||
| current = ExceptionUtil.getCause( current, true ) ) | |||
| { | |||
| final String causeMessage = REZ.getString( "cause.error", current.getMessage() ); | |||
| buffer.append( causeMessage ); | |||
| } | |||
| message = buffer.toString(); | |||
| } | |||
| // Write the message out | |||
| if( getLogger() == null ) | |||
| { | |||
| System.err.println( message ); | |||
| } | |||
| else | |||
| { | |||
| getLogger().error( message ); | |||
| } | |||
| } | |||
| private void executeBuild( final Embeddor embeddor, | |||
| final Project project, | |||
| final ProjectListener listener ) | |||
| @@ -416,9 +474,9 @@ public class CLIMain | |||
| return buildFile; | |||
| } | |||
| private File getHomeDir() throws Exception | |||
| private void checkHomeDir() throws Exception | |||
| { | |||
| final String home = m_parameters.getParameter( "myrmidon.home", null ); | |||
| final String home = m_parameters.getParameter( "myrmidon.home" ); | |||
| final File homeDir = ( new File( home ) ).getAbsoluteFile(); | |||
| if( !homeDir.isDirectory() ) | |||
| { | |||
| @@ -431,15 +489,12 @@ public class CLIMain | |||
| final String message = REZ.getString( "homedir.notice", homeDir ); | |||
| getLogger().info( message ); | |||
| } | |||
| return homeDir; | |||
| } | |||
| private void prepareLogging() throws Exception | |||
| { | |||
| //handle logging... | |||
| final String logLevel = m_parameters.getParameter( "log.level", null ); | |||
| enableLogging( new LogKitLogger( createLogger( logLevel ) ) ); | |||
| enableLogging( new LogKitLogger( createLogger( m_priority ) ) ); | |||
| } | |||
| private void shutdownEmbeddor( final Embeddor embeddor ) | |||
| @@ -486,51 +541,49 @@ public class CLIMain | |||
| private void doBuild( final Workspace workspace, | |||
| final Project project, | |||
| final ArrayList targets ) | |||
| throws TaskException | |||
| { | |||
| try | |||
| { | |||
| final int targetCount = targets.size(); | |||
| final int targetCount = targets.size(); | |||
| //if we didn't specify a target on CLI then choose default | |||
| if( 0 == targetCount ) | |||
| { | |||
| workspace.executeProject( project, project.getDefaultTargetName() ); | |||
| } | |||
| else | |||
| { | |||
| for( int i = 0; i < targetCount; i++ ) | |||
| { | |||
| workspace.executeProject( project, (String)targets.get( i ) ); | |||
| } | |||
| } | |||
| //if we didn't specify a target on CLI then choose default | |||
| if( 0 == targetCount ) | |||
| { | |||
| workspace.executeProject( project, project.getDefaultTargetName() ); | |||
| } | |||
| catch( final TaskException ae ) | |||
| else | |||
| { | |||
| final String message = | |||
| REZ.getString( "build-failed.error", ExceptionUtil.printStackTrace( ae, 5, true ) ); | |||
| getLogger().error( message ); | |||
| for( int i = 0; i < targetCount; i++ ) | |||
| { | |||
| workspace.executeProject( project, (String)targets.get( i ) ); | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Create Logger of appropriate log-level. | |||
| * | |||
| * @param logLevel the log-level | |||
| * @return the logger | |||
| * @exception Exception if an error occurs | |||
| * Sets the log level. | |||
| */ | |||
| private Logger createLogger( final String logLevel ) | |||
| throws Exception | |||
| private Priority mapLogLevel( final String logLevel ) throws Exception | |||
| { | |||
| final String logLevelCapitalized = logLevel.toUpperCase(); | |||
| final Priority priority = Priority.getPriorityForName( logLevelCapitalized ); | |||
| if( !priority.getName().equals( logLevelCapitalized ) ) | |||
| { | |||
| final String message = REZ.getString( "bad-loglevel.error", logLevel ); | |||
| throw new Exception( message ); | |||
| } | |||
| return priority; | |||
| } | |||
| /** | |||
| * Create Logger of appropriate log-level. | |||
| * | |||
| * @param priority the log-level | |||
| * @return the logger | |||
| * @exception Exception if an error occurs | |||
| */ | |||
| private Logger createLogger( final Priority priority ) | |||
| throws Exception | |||
| { | |||
| final Logger logger = Hierarchy.getDefaultHierarchy().getLoggerFor( "myrmidon" ); | |||
| final PatternFormatter formatter = new PatternFormatter( PATTERN ); | |||
| @@ -18,7 +18,8 @@ dry-run.opt=Do not execute tasks - just print them out. | |||
| home-not-dir.error=myrmidon-home ({0}) is not a directory. | |||
| bad-file.error=File {0} is not a file or doesn't exist. | |||
| bad-loglevel.error=Unknown log level - {0}. | |||
| build-failed.error=BUILD FAILED\nReason:\n{0} | |||
| build-failed.error=BUILD FAILED. | |||
| cause.error=\nReason: {0} | |||
| repeat.notice=Continue ? (Enter no to stop) | |||
| @@ -83,11 +83,14 @@ public class IfTest | |||
| final File projectFile = getTestResource( "if.ant" ); | |||
| // Check for missing condition | |||
| String message = REZ.getString( "if.no-condition.error" ); | |||
| executeTargetExpectError( projectFile, "no-condition", message ); | |||
| String[] messages = { | |||
| null, | |||
| REZ.getString( "if.no-condition.error" ) | |||
| }; | |||
| executeTargetExpectError( projectFile, "no-condition", messages ); | |||
| // Check for too many conditions | |||
| String[] messages = | |||
| messages = new String[] | |||
| { | |||
| null, | |||
| null, | |||
| @@ -64,21 +64,31 @@ public class PropertyTest | |||
| final File projectFile = getTestResource( "property.ant" ); | |||
| // Missing name | |||
| String message = REZ.getString( "property.no-name.error" ); | |||
| executeTargetExpectError( projectFile, "missing-name", message ); | |||
| String[] messages = | |||
| { | |||
| null, | |||
| REZ.getString( "property.no-name.error" ) | |||
| }; | |||
| executeTargetExpectError( projectFile, "missing-name", messages ); | |||
| // Missing value | |||
| message = REZ.getString( "property.no-value.error" ); | |||
| executeTargetExpectError( projectFile, "missing-value", message ); | |||
| messages = new String[] | |||
| { | |||
| null, | |||
| REZ.getString( "property.no-value.error" ) | |||
| }; | |||
| executeTargetExpectError( projectFile, "missing-value", messages ); | |||
| // Too many values | |||
| String[] messages = { | |||
| messages = new String[] | |||
| { | |||
| null, | |||
| null, | |||
| REZ.getString( "property.multi-set.error" ) | |||
| }; | |||
| executeTargetExpectError( projectFile, "too-many-values1", messages ); | |||
| executeTargetExpectError( projectFile, "too-many-values2", messages ); | |||
| executeTargetExpectError( projectFile, "too-many-values3", messages ); | |||
| } | |||
| } | |||
| @@ -83,11 +83,14 @@ public class IfTest | |||
| final File projectFile = getTestResource( "if.ant" ); | |||
| // Check for missing condition | |||
| String message = REZ.getString( "if.no-condition.error" ); | |||
| executeTargetExpectError( projectFile, "no-condition", message ); | |||
| String[] messages = { | |||
| null, | |||
| REZ.getString( "if.no-condition.error" ) | |||
| }; | |||
| executeTargetExpectError( projectFile, "no-condition", messages ); | |||
| // Check for too many conditions | |||
| String[] messages = | |||
| messages = new String[] | |||
| { | |||
| null, | |||
| null, | |||
| @@ -64,21 +64,31 @@ public class PropertyTest | |||
| final File projectFile = getTestResource( "property.ant" ); | |||
| // Missing name | |||
| String message = REZ.getString( "property.no-name.error" ); | |||
| executeTargetExpectError( projectFile, "missing-name", message ); | |||
| String[] messages = | |||
| { | |||
| null, | |||
| REZ.getString( "property.no-name.error" ) | |||
| }; | |||
| executeTargetExpectError( projectFile, "missing-name", messages ); | |||
| // Missing value | |||
| message = REZ.getString( "property.no-value.error" ); | |||
| executeTargetExpectError( projectFile, "missing-value", message ); | |||
| messages = new String[] | |||
| { | |||
| null, | |||
| REZ.getString( "property.no-value.error" ) | |||
| }; | |||
| executeTargetExpectError( projectFile, "missing-value", messages ); | |||
| // Too many values | |||
| String[] messages = { | |||
| messages = new String[] | |||
| { | |||
| null, | |||
| null, | |||
| REZ.getString( "property.multi-set.error" ) | |||
| }; | |||
| executeTargetExpectError( projectFile, "too-many-values1", messages ); | |||
| executeTargetExpectError( projectFile, "too-many-values2", messages ); | |||
| executeTargetExpectError( projectFile, "too-many-values3", messages ); | |||
| } | |||
| } | |||