Initial stages involves just making the Ant1.x tasks implement Ant2 interface and refactoring BuildException such that it can be easily be replaced by TaskException etc. git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@270153 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -0,0 +1,138 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant; | |||
| import java.util.EventObject; | |||
| public class BuildEvent extends EventObject | |||
| { | |||
| private int priority = Project.MSG_VERBOSE; | |||
| private Throwable exception; | |||
| private String message; | |||
| private Project project; | |||
| private Target target; | |||
| private Task task; | |||
| /** | |||
| * Construct a BuildEvent for a project level event | |||
| * | |||
| * @param project the project that emitted the event. | |||
| */ | |||
| public BuildEvent( Project project ) | |||
| { | |||
| super( project ); | |||
| this.project = project; | |||
| this.target = null; | |||
| this.task = null; | |||
| } | |||
| /** | |||
| * Construct a BuildEvent for a target level event | |||
| * | |||
| * @param target the target that emitted the event. | |||
| */ | |||
| public BuildEvent( Target target ) | |||
| { | |||
| super( target ); | |||
| this.project = target.getProject(); | |||
| this.target = target; | |||
| this.task = null; | |||
| } | |||
| /** | |||
| * Construct a BuildEvent for a task level event | |||
| * | |||
| * @param task the task that emitted the event. | |||
| */ | |||
| public BuildEvent( Task task ) | |||
| { | |||
| super( task ); | |||
| this.project = task.getProject(); | |||
| this.target = task.getOwningTarget(); | |||
| this.task = task; | |||
| } | |||
| public void setException( Throwable exception ) | |||
| { | |||
| this.exception = exception; | |||
| } | |||
| public void setMessage( String message, int priority ) | |||
| { | |||
| this.message = message; | |||
| this.priority = priority; | |||
| } | |||
| /** | |||
| * Returns the exception that was thrown, if any. This field will only be | |||
| * set for "taskFinished", "targetFinished", and "buildFinished" events. | |||
| * | |||
| * @return The Exception value | |||
| * @see BuildListener#taskFinished(BuildEvent) | |||
| * @see BuildListener#targetFinished(BuildEvent) | |||
| * @see BuildListener#buildFinished(BuildEvent) | |||
| */ | |||
| public Throwable getException() | |||
| { | |||
| return exception; | |||
| } | |||
| /** | |||
| * Returns the logging message. This field will only be set for | |||
| * "messageLogged" events. | |||
| * | |||
| * @return The Message value | |||
| * @see BuildListener#messageLogged(BuildEvent) | |||
| */ | |||
| public String getMessage() | |||
| { | |||
| return message; | |||
| } | |||
| /** | |||
| * Returns the priority of the logging message. This field will only be set | |||
| * for "messageLogged" events. | |||
| * | |||
| * @return The Priority value | |||
| * @see BuildListener#messageLogged(BuildEvent) | |||
| */ | |||
| public int getPriority() | |||
| { | |||
| return priority; | |||
| } | |||
| /** | |||
| * Returns the project that fired this event. | |||
| * | |||
| * @return The Project value | |||
| */ | |||
| public Project getProject() | |||
| { | |||
| return project; | |||
| } | |||
| /** | |||
| * Returns the target that fired this event. | |||
| * | |||
| * @return The Target value | |||
| */ | |||
| public Target getTarget() | |||
| { | |||
| return target; | |||
| } | |||
| /** | |||
| * Returns the task that fired this event. | |||
| * | |||
| * @return The Task value | |||
| */ | |||
| public Task getTask() | |||
| { | |||
| return task; | |||
| } | |||
| } | |||
| @@ -0,0 +1,103 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| /** | |||
| * Signals an error condition during a build. | |||
| * | |||
| * @author James Duncan Davidson | |||
| */ | |||
| public class BuildException | |||
| extends TaskException | |||
| { | |||
| /** | |||
| * Location in the build file where the exception occured | |||
| */ | |||
| private Location location = Location.UNKNOWN_LOCATION; | |||
| /** | |||
| * Constructs an exception with the given descriptive message. | |||
| * | |||
| * @param msg Description of or information about the exception. | |||
| */ | |||
| public BuildException( String msg ) | |||
| { | |||
| super( msg ); | |||
| } | |||
| /** | |||
| * Constructs an exception with the given message and exception as a root | |||
| * cause. | |||
| * | |||
| * @param msg Description of or information about the exception. | |||
| * @param cause Throwable that might have cause this one. | |||
| */ | |||
| public BuildException( String msg, Throwable cause ) | |||
| { | |||
| super( msg, cause ); | |||
| } | |||
| /** | |||
| * Constructs an exception with the given message and exception as a root | |||
| * cause and a location in a file. | |||
| * | |||
| * @param msg Description of or information about the exception. | |||
| * @param cause Exception that might have cause this one. | |||
| * @param location Location in the project file where the error occured. | |||
| */ | |||
| public BuildException( String msg, Throwable cause, Location location ) | |||
| { | |||
| this( msg, cause ); | |||
| this.location = location; | |||
| } | |||
| /** | |||
| * Constructs an exception with the given exception as a root cause. | |||
| * | |||
| * @param cause Exception that might have caused this one. | |||
| */ | |||
| public BuildException( Throwable cause ) | |||
| { | |||
| super( cause.toString(), cause ); | |||
| } | |||
| /** | |||
| * Constructs an exception with the given descriptive message and a location | |||
| * in a file. | |||
| * | |||
| * @param msg Description of or information about the exception. | |||
| * @param location Location in the project file where the error occured. | |||
| */ | |||
| public BuildException( String msg, Location location ) | |||
| { | |||
| super( msg ); | |||
| this.location = location; | |||
| } | |||
| /** | |||
| * Sets the file location where the error occured. | |||
| * | |||
| * @param location The new Location value | |||
| */ | |||
| public void setLocation( Location location ) | |||
| { | |||
| this.location = location; | |||
| } | |||
| /** | |||
| * Returns the file location where the error occured. | |||
| * | |||
| * @return The Location value | |||
| */ | |||
| public Location getLocation() | |||
| { | |||
| return location; | |||
| } | |||
| } | |||
| @@ -0,0 +1,80 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant; | |||
| import java.util.EventListener; | |||
| /** | |||
| * Classes that implement this interface will be notified when things happend | |||
| * during a build. | |||
| * | |||
| * @author RT | |||
| * @see BuildEvent | |||
| * @see Project#addBuildListener(BuildListener) | |||
| */ | |||
| public interface BuildListener extends EventListener | |||
| { | |||
| /** | |||
| * Fired before any targets are started. | |||
| * | |||
| * @param event Description of Parameter | |||
| */ | |||
| void buildStarted( BuildEvent event ); | |||
| /** | |||
| * Fired after the last target has finished. This event will still be thrown | |||
| * if an error occured during the build. | |||
| * | |||
| * @param event Description of Parameter | |||
| * @see BuildEvent#getException() | |||
| */ | |||
| void buildFinished( BuildEvent event ); | |||
| /** | |||
| * Fired when a target is started. | |||
| * | |||
| * @param event Description of Parameter | |||
| * @see BuildEvent#getTarget() | |||
| */ | |||
| void targetStarted( BuildEvent event ); | |||
| /** | |||
| * Fired when a target has finished. This event will still be thrown if an | |||
| * error occured during the build. | |||
| * | |||
| * @param event Description of Parameter | |||
| * @see BuildEvent#getException() | |||
| */ | |||
| void targetFinished( BuildEvent event ); | |||
| /** | |||
| * Fired when a task is started. | |||
| * | |||
| * @param event Description of Parameter | |||
| * @see BuildEvent#getTask() | |||
| */ | |||
| void taskStarted( BuildEvent event ); | |||
| /** | |||
| * Fired when a task has finished. This event will still be throw if an | |||
| * error occured during the build. | |||
| * | |||
| * @param event Description of Parameter | |||
| * @see BuildEvent#getException() | |||
| */ | |||
| void taskFinished( BuildEvent event ); | |||
| /** | |||
| * Fired whenever a message is logged. | |||
| * | |||
| * @param event Description of Parameter | |||
| * @see BuildEvent#getMessage() | |||
| * @see BuildEvent#getPriority() | |||
| */ | |||
| void messageLogged( BuildEvent event ); | |||
| } | |||
| @@ -0,0 +1,54 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant; | |||
| import java.io.PrintStream; | |||
| /** | |||
| * Interface used by Ant to log the build output. A build logger is a build | |||
| * listener which has the 'right' to send output to the ant log, which is | |||
| * usually System.out unles redirected by the -logfile option. | |||
| * | |||
| * @author Conor MacNeill | |||
| */ | |||
| public interface BuildLogger extends BuildListener | |||
| { | |||
| /** | |||
| * Set the msgOutputLevel this logger is to respond to. Only messages with a | |||
| * message level lower than or equal to the given level are output to the | |||
| * log. <P> | |||
| * | |||
| * Constants for the message levels are in Project.java. The order of the | |||
| * levels, from least to most verbose, is MSG_ERR, MSG_WARN, MSG_INFO, | |||
| * MSG_VERBOSE, MSG_DEBUG. | |||
| * | |||
| * @param level the logging level for the logger. | |||
| */ | |||
| void setMessageOutputLevel( int level ); | |||
| /** | |||
| * Set the output stream to which this logger is to send its output. | |||
| * | |||
| * @param output the output stream for the logger. | |||
| */ | |||
| void setOutputPrintStream( PrintStream output ); | |||
| /** | |||
| * Set this logger to produce emacs (and other editor) friendly output. | |||
| * | |||
| * @param emacsMode true if output is to be unadorned so that emacs and | |||
| * other editors can parse files names, etc. | |||
| */ | |||
| void setEmacsMode( boolean emacsMode ); | |||
| /** | |||
| * Set the output stream to which this logger is to send error messages. | |||
| * | |||
| * @param err the error stream for the logger. | |||
| */ | |||
| void setErrorPrintStream( PrintStream err ); | |||
| } | |||
| @@ -0,0 +1,17 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant; | |||
| /** | |||
| * Abstract interface to hold constants. | |||
| * | |||
| * @author <a href="mailto:donaldp@apache.org">Peter Donald</a> | |||
| */ | |||
| interface Constants | |||
| { | |||
| } | |||
| @@ -0,0 +1,220 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant; | |||
| import java.io.PrintStream; | |||
| import java.io.PrintWriter; | |||
| import java.io.StringWriter; | |||
| import org.apache.tools.ant.util.StringUtils; | |||
| /** | |||
| * Writes build event to a PrintStream. Currently, it only writes which targets | |||
| * are being executed, and any messages that get logged. | |||
| * | |||
| * @author RT | |||
| */ | |||
| public class DefaultLogger implements BuildLogger | |||
| { | |||
| private static int LEFT_COLUMN_SIZE = 12; | |||
| protected int msgOutputLevel = Project.MSG_ERR; | |||
| private long startTime = System.currentTimeMillis(); | |||
| protected boolean emacsMode = false; | |||
| protected PrintStream err; | |||
| protected PrintStream out; | |||
| protected 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" ); | |||
| } | |||
| } | |||
| /** | |||
| * Set this logger to produce emacs (and other editor) friendly output. | |||
| * | |||
| * @param emacsMode true if output is to be unadorned so that emacs and | |||
| * other editors can parse files names, etc. | |||
| */ | |||
| public void setEmacsMode( boolean emacsMode ) | |||
| { | |||
| this.emacsMode = emacsMode; | |||
| } | |||
| /** | |||
| * Set the output stream to which this logger is to send error messages. | |||
| * | |||
| * @param err the error stream for the logger. | |||
| */ | |||
| public void setErrorPrintStream( PrintStream err ) | |||
| { | |||
| this.err = new PrintStream( err, true ); | |||
| } | |||
| /** | |||
| * Set the msgOutputLevel this logger is to respond to. Only messages with a | |||
| * message level lower than or equal to the given level are output to the | |||
| * log. <P> | |||
| * | |||
| * Constants for the message levels are in Project.java. The order of the | |||
| * levels, from least to most verbose, is MSG_ERR, MSG_WARN, MSG_INFO, | |||
| * MSG_VERBOSE, MSG_DEBUG. The default message level for DefaultLogger is | |||
| * Project.MSG_ERR. | |||
| * | |||
| * @param level the logging level for the logger. | |||
| */ | |||
| public void setMessageOutputLevel( int level ) | |||
| { | |||
| this.msgOutputLevel = level; | |||
| } | |||
| /** | |||
| * Set the output stream to which this logger is to send its output. | |||
| * | |||
| * @param output the output stream for the logger. | |||
| */ | |||
| public void setOutputPrintStream( PrintStream output ) | |||
| { | |||
| this.out = new PrintStream( output, true ); | |||
| } | |||
| /** | |||
| * Prints whether the build succeeded or failed, and any errors the occured | |||
| * during the build. | |||
| * | |||
| * @param event Description of Parameter | |||
| */ | |||
| public void buildFinished( BuildEvent event ) | |||
| { | |||
| Throwable error = event.getException(); | |||
| StringBuffer message = new StringBuffer(); | |||
| if( error == null ) | |||
| { | |||
| message.append( StringUtils.LINE_SEP ); | |||
| message.append( "BUILD SUCCESSFUL" ); | |||
| } | |||
| else | |||
| { | |||
| message.append( StringUtils.LINE_SEP ); | |||
| message.append( "BUILD FAILED" ); | |||
| message.append( StringUtils.LINE_SEP ); | |||
| if( Project.MSG_VERBOSE <= msgOutputLevel || | |||
| !( error instanceof BuildException ) ) | |||
| { | |||
| message.append( StringUtils.getStackTrace( error ) ); | |||
| } | |||
| else | |||
| { | |||
| if( error instanceof BuildException ) | |||
| { | |||
| message.append( error.toString() ).append( StringUtils.LINE_SEP ); | |||
| } | |||
| else | |||
| { | |||
| message.append( error.getMessage() ).append( StringUtils.LINE_SEP ); | |||
| } | |||
| } | |||
| } | |||
| message.append( StringUtils.LINE_SEP ); | |||
| message.append( "Total time: " | |||
| + formatTime( System.currentTimeMillis() - startTime ) ); | |||
| String msg = message.toString(); | |||
| if( error == null ) | |||
| { | |||
| out.println( msg ); | |||
| } | |||
| else | |||
| { | |||
| err.println( msg ); | |||
| } | |||
| log( msg ); | |||
| } | |||
| public void buildStarted( BuildEvent event ) | |||
| { | |||
| startTime = System.currentTimeMillis(); | |||
| } | |||
| public void messageLogged( BuildEvent event ) | |||
| { | |||
| // Filter out messages based on priority | |||
| if( event.getPriority() <= msgOutputLevel ) | |||
| { | |||
| StringBuffer message = new StringBuffer(); | |||
| // Print out the name of the task if we're in one | |||
| if( event.getTask() != null ) | |||
| { | |||
| String name = event.getTask().getTaskName(); | |||
| if( !emacsMode ) | |||
| { | |||
| String label = "[" + name + "] "; | |||
| for( int i = 0; i < ( LEFT_COLUMN_SIZE - label.length() ); i++ ) | |||
| { | |||
| message.append( " " ); | |||
| } | |||
| message.append( label ); | |||
| } | |||
| } | |||
| message.append( event.getMessage() ); | |||
| String msg = message.toString(); | |||
| if( event.getPriority() != Project.MSG_ERR ) | |||
| { | |||
| out.println( msg ); | |||
| } | |||
| else | |||
| { | |||
| err.println( msg ); | |||
| } | |||
| log( msg ); | |||
| } | |||
| } | |||
| public void targetFinished( BuildEvent event ) { } | |||
| public void targetStarted( BuildEvent event ) | |||
| { | |||
| if( Project.MSG_INFO <= msgOutputLevel ) | |||
| { | |||
| String msg = StringUtils.LINE_SEP + event.getTarget().getName() + ":"; | |||
| out.println( msg ); | |||
| log( msg ); | |||
| } | |||
| } | |||
| public void taskFinished( BuildEvent event ) { } | |||
| public void taskStarted( BuildEvent event ) { } | |||
| /** | |||
| * Empty implementation which allows subclasses to receive the same output | |||
| * that is generated here. | |||
| * | |||
| * @param message Description of Parameter | |||
| */ | |||
| protected void log( String message ) { } | |||
| } | |||
| @@ -0,0 +1,127 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant; | |||
| import java.io.ByteArrayOutputStream; | |||
| import java.io.IOException; | |||
| import java.io.OutputStream; | |||
| import java.util.Hashtable; | |||
| /** | |||
| * Logs content written by a thread and forwards the buffers onto the project | |||
| * object which will forward the content to the appropriate task | |||
| * | |||
| * @author Conor MacNeill | |||
| */ | |||
| public class DemuxOutputStream extends OutputStream | |||
| { | |||
| private final static int MAX_SIZE = 1024; | |||
| private Hashtable buffers = new Hashtable(); | |||
| // private ByteArrayOutputStream buffer = new ByteArrayOutputStream(); | |||
| private boolean skip = false; | |||
| private boolean isErrorStream; | |||
| private Project project; | |||
| /** | |||
| * Creates a new instance of this class. | |||
| * | |||
| * @param project Description of Parameter | |||
| * @param isErrorStream Description of Parameter | |||
| */ | |||
| public DemuxOutputStream( Project project, boolean isErrorStream ) | |||
| { | |||
| this.project = project; | |||
| this.isErrorStream = isErrorStream; | |||
| } | |||
| /** | |||
| * Writes all remaining | |||
| * | |||
| * @exception IOException Description of Exception | |||
| */ | |||
| public void close() | |||
| throws IOException | |||
| { | |||
| flush(); | |||
| } | |||
| /** | |||
| * Writes all remaining | |||
| * | |||
| * @exception IOException Description of Exception | |||
| */ | |||
| public void flush() | |||
| throws IOException | |||
| { | |||
| if( getBuffer().size() > 0 ) | |||
| { | |||
| processBuffer(); | |||
| } | |||
| } | |||
| /** | |||
| * Write the data to the buffer and flush the buffer, if a line separator is | |||
| * detected. | |||
| * | |||
| * @param cc data to log (byte). | |||
| * @exception IOException Description of Exception | |||
| */ | |||
| public void write( int cc ) | |||
| throws IOException | |||
| { | |||
| final byte c = ( byte )cc; | |||
| if( ( c == '\n' ) || ( c == '\r' ) ) | |||
| { | |||
| if( !skip ) | |||
| { | |||
| processBuffer(); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| ByteArrayOutputStream buffer = getBuffer(); | |||
| buffer.write( cc ); | |||
| if( buffer.size() > MAX_SIZE ) | |||
| { | |||
| processBuffer(); | |||
| } | |||
| } | |||
| skip = ( c == '\r' ); | |||
| } | |||
| /** | |||
| * Converts the buffer to a string and sends it to <code>processLine</code> | |||
| */ | |||
| protected void processBuffer() | |||
| { | |||
| String output = getBuffer().toString(); | |||
| project.demuxOutput( output, isErrorStream ); | |||
| resetBuffer(); | |||
| } | |||
| private ByteArrayOutputStream getBuffer() | |||
| { | |||
| Thread current = Thread.currentThread(); | |||
| ByteArrayOutputStream buffer = ( ByteArrayOutputStream )buffers.get( current ); | |||
| if( buffer == null ) | |||
| { | |||
| buffer = new ByteArrayOutputStream(); | |||
| buffers.put( current, buffer ); | |||
| } | |||
| return buffer; | |||
| } | |||
| private void resetBuffer() | |||
| { | |||
| Thread current = Thread.currentThread(); | |||
| buffers.remove( current ); | |||
| } | |||
| } | |||
| @@ -0,0 +1,96 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant; | |||
| import java.io.File; | |||
| import java.io.FilenameFilter; | |||
| /** | |||
| * Filters filenames to determine whether or not the file is desirable. | |||
| * | |||
| * @author Jason Hunter [jhunter@servlets.com] | |||
| * @author james@x180.com | |||
| */ | |||
| public class DesirableFilter implements FilenameFilter | |||
| { | |||
| /** | |||
| * Test the given filename to determine whether or not it's desirable. This | |||
| * helps tasks filter temp files and files used by CVS. | |||
| * | |||
| * @param dir Description of Parameter | |||
| * @param name Description of Parameter | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public boolean accept( File dir, String name ) | |||
| { | |||
| // emacs save file | |||
| if( name.endsWith( "~" ) ) | |||
| { | |||
| return false; | |||
| } | |||
| // emacs autosave file | |||
| if( name.startsWith( "#" ) && name.endsWith( "#" ) ) | |||
| { | |||
| return false; | |||
| } | |||
| // openwindows text editor does this I think | |||
| if( name.startsWith( "%" ) && name.endsWith( "%" ) ) | |||
| { | |||
| return false; | |||
| } | |||
| /* | |||
| * CVS stuff -- hopefully there won't be a case with | |||
| * an all cap file/dir named "CVS" that somebody wants | |||
| * to keep around... | |||
| */ | |||
| if( name.equals( "CVS" ) ) | |||
| { | |||
| return false; | |||
| } | |||
| /* | |||
| * If we are going to ignore CVS might as well ignore | |||
| * this one as well... | |||
| */ | |||
| if( name.equals( ".cvsignore" ) ) | |||
| { | |||
| return false; | |||
| } | |||
| // CVS merge autosaves. | |||
| if( name.startsWith( ".#" ) ) | |||
| { | |||
| return false; | |||
| } | |||
| // SCCS/CSSC/TeamWare: | |||
| if( name.equals( "SCCS" ) ) | |||
| { | |||
| return false; | |||
| } | |||
| // Visual Source Save | |||
| if( name.equals( "vssver.scc" ) ) | |||
| { | |||
| return false; | |||
| } | |||
| // default | |||
| return true; | |||
| } | |||
| } | |||
| @@ -0,0 +1,39 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant; | |||
| /** | |||
| * Used to report exit status of classes which call System.exit() | |||
| * | |||
| * @author Conor MacNeill | |||
| * @see NoExitSecurityManager | |||
| */ | |||
| public class ExitException extends SecurityException | |||
| { | |||
| private int status; | |||
| /** | |||
| * Constructs an exit exception. | |||
| * | |||
| * @param status the status code returned via System.exit() | |||
| */ | |||
| public ExitException( int status ) | |||
| { | |||
| super( "ExitException: status " + status ); | |||
| this.status = status; | |||
| } | |||
| /** | |||
| * @return the status code return via System.exit() | |||
| */ | |||
| public int getStatus() | |||
| { | |||
| return status; | |||
| } | |||
| } | |||
| @@ -0,0 +1,127 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant; | |||
| import java.io.File; | |||
| /** | |||
| * An interface used to describe the actions required by any type of directory | |||
| * scanner. | |||
| * | |||
| * @author RT | |||
| */ | |||
| public interface FileScanner | |||
| { | |||
| /** | |||
| * Adds an array with default exclusions to the current exclusions set. | |||
| */ | |||
| void addDefaultExcludes(); | |||
| /** | |||
| * Gets the basedir that is used for scanning. This is the directory that is | |||
| * scanned recursively. | |||
| * | |||
| * @return the basedir that is used for scanning | |||
| */ | |||
| File getBasedir(); | |||
| /** | |||
| * Get the names of the directories that matched at least one of the include | |||
| * patterns, an matched also at least one of the exclude patterns. The names | |||
| * are relative to the basedir. | |||
| * | |||
| * @return the names of the directories | |||
| */ | |||
| String[] getExcludedDirectories(); | |||
| /** | |||
| * Get the names of the files that matched at least one of the include | |||
| * patterns, an matched also at least one of the exclude patterns. The names | |||
| * are relative to the basedir. | |||
| * | |||
| * @return the names of the files | |||
| */ | |||
| String[] getExcludedFiles(); | |||
| /** | |||
| * Get the names of the directories that matched at least one of the include | |||
| * patterns, an matched none of the exclude patterns. The names are relative | |||
| * to the basedir. | |||
| * | |||
| * @return the names of the directories | |||
| */ | |||
| String[] getIncludedDirectories(); | |||
| /** | |||
| * Get the names of the files that matched at least one of the include | |||
| * patterns, an matched none of the exclude patterns. The names are relative | |||
| * to the basedir. | |||
| * | |||
| * @return the names of the files | |||
| */ | |||
| String[] getIncludedFiles(); | |||
| /** | |||
| * Get the names of the directories that matched at none of the include | |||
| * patterns. The names are relative to the basedir. | |||
| * | |||
| * @return the names of the directories | |||
| */ | |||
| String[] getNotIncludedDirectories(); | |||
| /** | |||
| * Get the names of the files that matched at none of the include patterns. | |||
| * The names are relative to the basedir. | |||
| * | |||
| * @return the names of the files | |||
| */ | |||
| String[] getNotIncludedFiles(); | |||
| /** | |||
| * Scans the base directory for files that match at least one include | |||
| * pattern, and don't match any exclude patterns. | |||
| * | |||
| */ | |||
| void scan(); | |||
| /** | |||
| * Sets the basedir for scanning. This is the directory that is scanned | |||
| * recursively. | |||
| * | |||
| * @param basedir the (non-null) basedir for scanning | |||
| */ | |||
| void setBasedir( String basedir ); | |||
| /** | |||
| * Sets the basedir for scanning. This is the directory that is scanned | |||
| * recursively. | |||
| * | |||
| * @param basedir the basedir for scanning | |||
| */ | |||
| void setBasedir( File basedir ); | |||
| /** | |||
| * Sets the set of exclude patterns to use. | |||
| * | |||
| * @param excludes list of exclude patterns | |||
| */ | |||
| void setExcludes( String[] excludes ); | |||
| /** | |||
| * Sets the set of include patterns to use. | |||
| * | |||
| * @param includes list of include patterns | |||
| */ | |||
| void setIncludes( String[] includes ); | |||
| /** | |||
| * Sets the case sensitivity of the file system | |||
| * | |||
| * @param isCaseSensitive The new CaseSensitive value | |||
| */ | |||
| void setCaseSensitive( boolean isCaseSensitive ); | |||
| } | |||
| @@ -0,0 +1,848 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant; | |||
| import java.io.File; | |||
| import java.lang.reflect.Constructor; | |||
| import java.lang.reflect.InvocationTargetException; | |||
| import java.lang.reflect.Method; | |||
| import java.util.Enumeration; | |||
| import java.util.Hashtable; | |||
| import java.util.Locale; | |||
| import org.apache.tools.ant.types.EnumeratedAttribute; | |||
| import org.apache.tools.ant.types.Path; | |||
| /** | |||
| * Helper class that collects the methods a task or nested element holds to set | |||
| * attributes, create nested elements or hold PCDATA elements. | |||
| * | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| */ | |||
| public class IntrospectionHelper implements BuildListener | |||
| { | |||
| /** | |||
| * instances we've already created | |||
| */ | |||
| private static Hashtable helpers = new Hashtable(); | |||
| /** | |||
| * The method to add PCDATA stuff. | |||
| */ | |||
| private Method addText = null; | |||
| /** | |||
| * holds the attribute setter methods. | |||
| */ | |||
| private Hashtable attributeSetters; | |||
| /** | |||
| * holds the types of the attributes that could be set. | |||
| */ | |||
| private Hashtable attributeTypes; | |||
| /** | |||
| * The Class that's been introspected. | |||
| */ | |||
| private Class bean; | |||
| /** | |||
| * Holds methods to create nested elements. | |||
| */ | |||
| private Hashtable nestedCreators; | |||
| /** | |||
| * Holds methods to store configured nested elements. | |||
| */ | |||
| private Hashtable nestedStorers; | |||
| /** | |||
| * Holds the types of nested elements that could be created. | |||
| */ | |||
| private Hashtable nestedTypes; | |||
| private IntrospectionHelper( final Class bean ) | |||
| { | |||
| attributeTypes = new Hashtable(); | |||
| attributeSetters = new Hashtable(); | |||
| nestedTypes = new Hashtable(); | |||
| nestedCreators = new Hashtable(); | |||
| nestedStorers = new Hashtable(); | |||
| this.bean = bean; | |||
| Method[] methods = bean.getMethods(); | |||
| for( int i = 0; i < methods.length; i++ ) | |||
| { | |||
| final Method m = methods[i]; | |||
| final String name = m.getName(); | |||
| Class returnType = m.getReturnType(); | |||
| Class[] args = m.getParameterTypes(); | |||
| // not really user settable properties on tasks | |||
| if( org.apache.tools.ant.Task.class.isAssignableFrom( bean ) | |||
| && args.length == 1 && | |||
| ( | |||
| ( | |||
| "setLocation".equals( name ) && org.apache.tools.ant.Location.class.equals( args[0] ) | |||
| ) || ( | |||
| "setTaskType".equals( name ) && java.lang.String.class.equals( args[0] ) | |||
| ) | |||
| ) ) | |||
| { | |||
| continue; | |||
| } | |||
| // hide addTask for TaskContainers | |||
| if( org.apache.tools.ant.TaskContainer.class.isAssignableFrom( bean ) | |||
| && args.length == 1 && "addTask".equals( name ) | |||
| && org.apache.tools.ant.Task.class.equals( args[0] ) ) | |||
| { | |||
| continue; | |||
| } | |||
| if( "addText".equals( name ) | |||
| && java.lang.Void.TYPE.equals( returnType ) | |||
| && args.length == 1 | |||
| && java.lang.String.class.equals( args[0] ) ) | |||
| { | |||
| addText = methods[i]; | |||
| } | |||
| else if( name.startsWith( "set" ) | |||
| && java.lang.Void.TYPE.equals( returnType ) | |||
| && args.length == 1 | |||
| && !args[0].isArray() ) | |||
| { | |||
| String propName = getPropertyName( name, "set" ); | |||
| if( attributeSetters.get( propName ) != null ) | |||
| { | |||
| if( java.lang.String.class.equals( args[0] ) ) | |||
| { | |||
| /* | |||
| * Ignore method m, as there is an overloaded | |||
| * form of this method that takes in a | |||
| * non-string argument, which gains higher | |||
| * priority. | |||
| */ | |||
| continue; | |||
| } | |||
| /* | |||
| * If the argument is not a String, and if there | |||
| * is an overloaded form of this method already defined, | |||
| * we just override that with the new one. | |||
| * This mechanism does not guarantee any specific order | |||
| * in which the methods will be selected: so any code | |||
| * that depends on the order in which "set" methods have | |||
| * been defined, is not guaranteed to be selected in any | |||
| * particular order. | |||
| */ | |||
| } | |||
| AttributeSetter as = createAttributeSetter( m, args[0] ); | |||
| if( as != null ) | |||
| { | |||
| attributeTypes.put( propName, args[0] ); | |||
| attributeSetters.put( propName, as ); | |||
| } | |||
| } | |||
| else if( name.startsWith( "create" ) | |||
| && !returnType.isArray() | |||
| && !returnType.isPrimitive() | |||
| && args.length == 0 ) | |||
| { | |||
| String propName = getPropertyName( name, "create" ); | |||
| nestedTypes.put( propName, returnType ); | |||
| nestedCreators.put( propName, | |||
| new NestedCreator() | |||
| { | |||
| public Object create( Object parent ) | |||
| throws InvocationTargetException, | |||
| IllegalAccessException | |||
| { | |||
| return m.invoke( parent, new Object[]{} ); | |||
| } | |||
| } ); | |||
| } | |||
| else if( name.startsWith( "addConfigured" ) | |||
| && java.lang.Void.TYPE.equals( returnType ) | |||
| && args.length == 1 | |||
| && !java.lang.String.class.equals( args[0] ) | |||
| && !args[0].isArray() | |||
| && !args[0].isPrimitive() ) | |||
| { | |||
| try | |||
| { | |||
| final Constructor c = | |||
| args[0].getConstructor( new Class[]{} ); | |||
| String propName = getPropertyName( name, "addConfigured" ); | |||
| nestedTypes.put( propName, args[0] ); | |||
| nestedCreators.put( propName, | |||
| new NestedCreator() | |||
| { | |||
| public Object create( Object parent ) | |||
| throws InvocationTargetException, IllegalAccessException, InstantiationException | |||
| { | |||
| Object o = c.newInstance( new Object[]{} ); | |||
| return o; | |||
| } | |||
| } ); | |||
| nestedStorers.put( propName, | |||
| new NestedStorer() | |||
| { | |||
| public void store( Object parent, Object child ) | |||
| throws InvocationTargetException, IllegalAccessException, InstantiationException | |||
| { | |||
| m.invoke( parent, new Object[]{child} ); | |||
| } | |||
| } ); | |||
| } | |||
| catch( NoSuchMethodException nse ) | |||
| { | |||
| } | |||
| } | |||
| else if( name.startsWith( "add" ) | |||
| && java.lang.Void.TYPE.equals( returnType ) | |||
| && args.length == 1 | |||
| && !java.lang.String.class.equals( args[0] ) | |||
| && !args[0].isArray() | |||
| && !args[0].isPrimitive() ) | |||
| { | |||
| try | |||
| { | |||
| final Constructor c = | |||
| args[0].getConstructor( new Class[]{} ); | |||
| String propName = getPropertyName( name, "add" ); | |||
| nestedTypes.put( propName, args[0] ); | |||
| nestedCreators.put( propName, | |||
| new NestedCreator() | |||
| { | |||
| public Object create( Object parent ) | |||
| throws InvocationTargetException, IllegalAccessException, InstantiationException | |||
| { | |||
| Object o = c.newInstance( new Object[]{} ); | |||
| m.invoke( parent, new Object[]{o} ); | |||
| return o; | |||
| } | |||
| } ); | |||
| } | |||
| catch( NoSuchMethodException nse ) | |||
| { | |||
| } | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Factory method for helper objects. | |||
| * | |||
| * @param c Description of Parameter | |||
| * @return The Helper value | |||
| */ | |||
| public static synchronized IntrospectionHelper getHelper( Class c ) | |||
| { | |||
| IntrospectionHelper ih = ( IntrospectionHelper )helpers.get( c ); | |||
| if( ih == null ) | |||
| { | |||
| ih = new IntrospectionHelper( c ); | |||
| helpers.put( c, ih ); | |||
| } | |||
| return ih; | |||
| } | |||
| /** | |||
| * Sets the named attribute. | |||
| * | |||
| * @param p The new Attribute value | |||
| * @param element The new Attribute value | |||
| * @param attributeName The new Attribute value | |||
| * @param value The new Attribute value | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| public void setAttribute( Project p, Object element, String attributeName, | |||
| String value ) | |||
| throws BuildException | |||
| { | |||
| AttributeSetter as = ( AttributeSetter )attributeSetters.get( attributeName ); | |||
| if( as == null ) | |||
| { | |||
| String msg = getElementName( p, element ) + | |||
| //String msg = "Class " + element.getClass().getName() + | |||
| " doesn't support the \"" + attributeName + "\" attribute."; | |||
| throw new BuildException( msg ); | |||
| } | |||
| try | |||
| { | |||
| as.set( p, element, value ); | |||
| } | |||
| catch( IllegalAccessException ie ) | |||
| { | |||
| // impossible as getMethods should only return public methods | |||
| throw new BuildException( ie ); | |||
| } | |||
| catch( InvocationTargetException ite ) | |||
| { | |||
| Throwable t = ite.getTargetException(); | |||
| if( t instanceof BuildException ) | |||
| { | |||
| throw ( BuildException )t; | |||
| } | |||
| throw new BuildException( t ); | |||
| } | |||
| } | |||
| /** | |||
| * returns the type of a named attribute. | |||
| * | |||
| * @param attributeName Description of Parameter | |||
| * @return The AttributeType value | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| public Class getAttributeType( String attributeName ) | |||
| throws BuildException | |||
| { | |||
| Class at = ( Class )attributeTypes.get( attributeName ); | |||
| if( at == null ) | |||
| { | |||
| String msg = "Class " + bean.getName() + | |||
| " doesn't support the \"" + attributeName + "\" attribute."; | |||
| throw new BuildException( msg ); | |||
| } | |||
| return at; | |||
| } | |||
| /** | |||
| * Return all attribues supported by the introspected class. | |||
| * | |||
| * @return The Attributes value | |||
| */ | |||
| public Enumeration getAttributes() | |||
| { | |||
| return attributeSetters.keys(); | |||
| } | |||
| /** | |||
| * returns the type of a named nested element. | |||
| * | |||
| * @param elementName Description of Parameter | |||
| * @return The ElementType value | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| public Class getElementType( String elementName ) | |||
| throws BuildException | |||
| { | |||
| Class nt = ( Class )nestedTypes.get( elementName ); | |||
| if( nt == null ) | |||
| { | |||
| String msg = "Class " + bean.getName() + | |||
| " doesn't support the nested \"" + elementName + "\" element."; | |||
| throw new BuildException( msg ); | |||
| } | |||
| return nt; | |||
| } | |||
| /** | |||
| * Return all nested elements supported by the introspected class. | |||
| * | |||
| * @return The NestedElements value | |||
| */ | |||
| public Enumeration getNestedElements() | |||
| { | |||
| return nestedTypes.keys(); | |||
| } | |||
| /** | |||
| * Adds PCDATA areas. | |||
| * | |||
| * @param project The feature to be added to the Text attribute | |||
| * @param element The feature to be added to the Text attribute | |||
| * @param text The feature to be added to the Text attribute | |||
| */ | |||
| public void addText( Project project, Object element, String text ) | |||
| { | |||
| if( addText == null ) | |||
| { | |||
| String msg = getElementName( project, element ) + | |||
| //String msg = "Class " + element.getClass().getName() + | |||
| " doesn't support nested text data."; | |||
| throw new BuildException( msg ); | |||
| } | |||
| try | |||
| { | |||
| addText.invoke( element, new String[]{text} ); | |||
| } | |||
| catch( IllegalAccessException ie ) | |||
| { | |||
| // impossible as getMethods should only return public methods | |||
| throw new BuildException( ie ); | |||
| } | |||
| catch( InvocationTargetException ite ) | |||
| { | |||
| Throwable t = ite.getTargetException(); | |||
| if( t instanceof BuildException ) | |||
| { | |||
| throw ( BuildException )t; | |||
| } | |||
| throw new BuildException( t ); | |||
| } | |||
| } | |||
| public void buildFinished( BuildEvent event ) | |||
| { | |||
| attributeTypes.clear(); | |||
| attributeSetters.clear(); | |||
| nestedTypes.clear(); | |||
| nestedCreators.clear(); | |||
| addText = null; | |||
| helpers.clear(); | |||
| } | |||
| public void buildStarted( BuildEvent event ) { } | |||
| /** | |||
| * Creates a named nested element. | |||
| * | |||
| * @param project Description of Parameter | |||
| * @param element Description of Parameter | |||
| * @param elementName Description of Parameter | |||
| * @return Description of the Returned Value | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| public Object createElement( Project project, Object element, String elementName ) | |||
| throws BuildException | |||
| { | |||
| NestedCreator nc = ( NestedCreator )nestedCreators.get( elementName ); | |||
| if( nc == null ) | |||
| { | |||
| String msg = getElementName( project, element ) + | |||
| " doesn't support the nested \"" + elementName + "\" element."; | |||
| throw new BuildException( msg ); | |||
| } | |||
| try | |||
| { | |||
| Object nestedElement = nc.create( element ); | |||
| if( nestedElement instanceof ProjectComponent ) | |||
| { | |||
| ( ( ProjectComponent )nestedElement ).setProject( project ); | |||
| } | |||
| return nestedElement; | |||
| } | |||
| catch( IllegalAccessException ie ) | |||
| { | |||
| // impossible as getMethods should only return public methods | |||
| throw new BuildException( ie ); | |||
| } | |||
| catch( InstantiationException ine ) | |||
| { | |||
| // impossible as getMethods should only return public methods | |||
| throw new BuildException( ine ); | |||
| } | |||
| catch( InvocationTargetException ite ) | |||
| { | |||
| Throwable t = ite.getTargetException(); | |||
| if( t instanceof BuildException ) | |||
| { | |||
| throw ( BuildException )t; | |||
| } | |||
| throw new BuildException( t ); | |||
| } | |||
| } | |||
| public void messageLogged( BuildEvent event ) { } | |||
| /** | |||
| * Creates a named nested element. | |||
| * | |||
| * @param project Description of Parameter | |||
| * @param element Description of Parameter | |||
| * @param child Description of Parameter | |||
| * @param elementName Description of Parameter | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| public void storeElement( Project project, Object element, Object child, String elementName ) | |||
| throws BuildException | |||
| { | |||
| if( elementName == null ) | |||
| { | |||
| return; | |||
| } | |||
| NestedStorer ns = ( NestedStorer )nestedStorers.get( elementName ); | |||
| if( ns == null ) | |||
| { | |||
| return; | |||
| } | |||
| try | |||
| { | |||
| ns.store( element, child ); | |||
| } | |||
| catch( IllegalAccessException ie ) | |||
| { | |||
| // impossible as getMethods should only return public methods | |||
| throw new BuildException( ie ); | |||
| } | |||
| catch( InstantiationException ine ) | |||
| { | |||
| // impossible as getMethods should only return public methods | |||
| throw new BuildException( ine ); | |||
| } | |||
| catch( InvocationTargetException ite ) | |||
| { | |||
| Throwable t = ite.getTargetException(); | |||
| if( t instanceof BuildException ) | |||
| { | |||
| throw ( BuildException )t; | |||
| } | |||
| throw new BuildException( t ); | |||
| } | |||
| } | |||
| /** | |||
| * Does the introspected class support PCDATA? | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public boolean supportsCharacters() | |||
| { | |||
| return addText != null; | |||
| } | |||
| public void targetFinished( BuildEvent event ) { } | |||
| public void targetStarted( BuildEvent event ) { } | |||
| public void taskFinished( BuildEvent event ) { } | |||
| public void taskStarted( BuildEvent event ) { } | |||
| protected String getElementName( Project project, Object element ) | |||
| { | |||
| Hashtable elements = project.getTaskDefinitions(); | |||
| String typeName = "task"; | |||
| if( !elements.contains( element.getClass() ) ) | |||
| { | |||
| elements = project.getDataTypeDefinitions(); | |||
| typeName = "data type"; | |||
| if( !elements.contains( element.getClass() ) ) | |||
| { | |||
| elements = null; | |||
| } | |||
| } | |||
| if( elements != null ) | |||
| { | |||
| Enumeration e = elements.keys(); | |||
| while( e.hasMoreElements() ) | |||
| { | |||
| String elementName = ( String )e.nextElement(); | |||
| Class elementClass = ( Class )elements.get( elementName ); | |||
| if( element.getClass().equals( elementClass ) ) | |||
| { | |||
| return "The <" + elementName + "> " + typeName; | |||
| } | |||
| } | |||
| } | |||
| return "Class " + element.getClass().getName(); | |||
| } | |||
| /** | |||
| * extract the name of a property from a method name - subtracting a given | |||
| * prefix. | |||
| * | |||
| * @param methodName Description of Parameter | |||
| * @param prefix Description of Parameter | |||
| * @return The PropertyName value | |||
| */ | |||
| private String getPropertyName( String methodName, String prefix ) | |||
| { | |||
| int start = prefix.length(); | |||
| return methodName.substring( start ).toLowerCase( Locale.US ); | |||
| } | |||
| /** | |||
| * Create a proper implementation of AttributeSetter for the given attribute | |||
| * type. | |||
| * | |||
| * @param m Description of Parameter | |||
| * @param arg Description of Parameter | |||
| * @return Description of the Returned Value | |||
| */ | |||
| private AttributeSetter createAttributeSetter( final Method m, | |||
| final Class arg ) | |||
| { | |||
| // simplest case - setAttribute expects String | |||
| if( java.lang.String.class.equals( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException | |||
| { | |||
| m.invoke( parent, new String[]{value} ); | |||
| } | |||
| }; | |||
| // now for the primitive types, use their wrappers | |||
| } | |||
| else if( java.lang.Character.class.equals( arg ) | |||
| || java.lang.Character.TYPE.equals( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException | |||
| { | |||
| m.invoke( parent, new Character[]{new Character( value.charAt( 0 ) )} ); | |||
| } | |||
| }; | |||
| } | |||
| else if( java.lang.Byte.TYPE.equals( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException | |||
| { | |||
| m.invoke( parent, new Byte[]{new Byte( value )} ); | |||
| } | |||
| }; | |||
| } | |||
| else if( java.lang.Short.TYPE.equals( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException | |||
| { | |||
| m.invoke( parent, new Short[]{new Short( value )} ); | |||
| } | |||
| }; | |||
| } | |||
| else if( java.lang.Integer.TYPE.equals( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException | |||
| { | |||
| m.invoke( parent, new Integer[]{new Integer( value )} ); | |||
| } | |||
| }; | |||
| } | |||
| else if( java.lang.Long.TYPE.equals( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException | |||
| { | |||
| m.invoke( parent, new Long[]{new Long( value )} ); | |||
| } | |||
| }; | |||
| } | |||
| else if( java.lang.Float.TYPE.equals( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException | |||
| { | |||
| m.invoke( parent, new Float[]{new Float( value )} ); | |||
| } | |||
| }; | |||
| } | |||
| else if( java.lang.Double.TYPE.equals( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException | |||
| { | |||
| m.invoke( parent, new Double[]{new Double( value )} ); | |||
| } | |||
| }; | |||
| // boolean gets an extra treatment, because we have a nice method | |||
| // in Project | |||
| } | |||
| else if( java.lang.Boolean.class.equals( arg ) | |||
| || java.lang.Boolean.TYPE.equals( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException | |||
| { | |||
| m.invoke( parent, | |||
| new Boolean[]{new Boolean( Project.toBoolean( value ) )} ); | |||
| } | |||
| }; | |||
| // Class doesn't have a String constructor but a decent factory method | |||
| } | |||
| else if( java.lang.Class.class.equals( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException, BuildException | |||
| { | |||
| try | |||
| { | |||
| m.invoke( parent, new Class[]{Class.forName( value )} ); | |||
| } | |||
| catch( ClassNotFoundException ce ) | |||
| { | |||
| throw new BuildException( ce ); | |||
| } | |||
| } | |||
| }; | |||
| // resolve relative paths through Project | |||
| } | |||
| else if( java.io.File.class.equals( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException | |||
| { | |||
| m.invoke( parent, new File[]{p.resolveFile( value )} ); | |||
| } | |||
| }; | |||
| // resolve relative paths through Project | |||
| } | |||
| else if( org.apache.tools.ant.types.Path.class.equals( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException | |||
| { | |||
| m.invoke( parent, new Path[]{new Path( p, value )} ); | |||
| } | |||
| }; | |||
| // EnumeratedAttributes have their own helper class | |||
| } | |||
| else if( org.apache.tools.ant.types.EnumeratedAttribute.class.isAssignableFrom( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException, BuildException | |||
| { | |||
| try | |||
| { | |||
| org.apache.tools.ant.types.EnumeratedAttribute ea = ( org.apache.tools.ant.types.EnumeratedAttribute )arg.newInstance(); | |||
| ea.setValue( value ); | |||
| m.invoke( parent, new EnumeratedAttribute[]{ea} ); | |||
| } | |||
| catch( InstantiationException ie ) | |||
| { | |||
| throw new BuildException( ie ); | |||
| } | |||
| } | |||
| }; | |||
| // worst case. look for a public String constructor and use it | |||
| } | |||
| else | |||
| { | |||
| try | |||
| { | |||
| final Constructor c = | |||
| arg.getConstructor( new Class[]{java.lang.String.class} ); | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, | |||
| String value ) | |||
| throws InvocationTargetException, IllegalAccessException, BuildException | |||
| { | |||
| try | |||
| { | |||
| Object attribute = c.newInstance( new String[]{value} ); | |||
| if( attribute instanceof ProjectComponent ) | |||
| { | |||
| ( ( ProjectComponent )attribute ).setProject( p ); | |||
| } | |||
| m.invoke( parent, new Object[]{attribute} ); | |||
| } | |||
| catch( InstantiationException ie ) | |||
| { | |||
| throw new BuildException( ie ); | |||
| } | |||
| } | |||
| }; | |||
| } | |||
| catch( NoSuchMethodException nme ) | |||
| { | |||
| } | |||
| } | |||
| return null; | |||
| } | |||
| private interface AttributeSetter | |||
| { | |||
| void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException, | |||
| BuildException; | |||
| } | |||
| private interface NestedCreator | |||
| { | |||
| Object create( Object parent ) | |||
| throws InvocationTargetException, IllegalAccessException, InstantiationException; | |||
| } | |||
| private interface NestedStorer | |||
| { | |||
| void store( Object parent, Object child ) | |||
| throws InvocationTargetException, IllegalAccessException, InstantiationException; | |||
| } | |||
| } | |||
| @@ -0,0 +1,182 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant; | |||
| import java.io.File; | |||
| import java.io.FilenameFilter; | |||
| import java.lang.reflect.Method; | |||
| import java.net.MalformedURLException; | |||
| import java.net.URL; | |||
| import java.util.Properties; | |||
| import java.util.StringTokenizer; | |||
| /** | |||
| * This is the Ant command line front end to end. This front end works out where | |||
| * ant is installed and loads the ant libraries before starting Ant proper. | |||
| * | |||
| * @author <a href="mailto:conor@apache.org">Conor MacNeill</a> | |||
| */ | |||
| public class Launcher | |||
| { | |||
| public static void main( String[] args ) | |||
| { | |||
| File antHome = null; | |||
| ClassLoader systemClassLoader = Launcher.class.getClassLoader(); | |||
| if( systemClassLoader == null ) | |||
| { | |||
| antHome = determineAntHome11(); | |||
| } | |||
| else | |||
| { | |||
| antHome = determineAntHome( systemClassLoader ); | |||
| } | |||
| if( antHome == null ) | |||
| { | |||
| System.err.println( "Unable to determine ANT_HOME" ); | |||
| System.exit( 1 ); | |||
| } | |||
| System.out.println( "ANT_HOME is " + antHome ); | |||
| // We now create the class loader with which we are going to launch ant | |||
| AntClassLoader antLoader = new AntClassLoader( systemClassLoader, false ); | |||
| // need to find tools.jar | |||
| addToolsJar( antLoader ); | |||
| // add everything in the lib directory to this classloader | |||
| File libDir = new File( antHome, "lib" ); | |||
| addDirJars( antLoader, libDir ); | |||
| File optionalDir = new File( antHome, "lib/optional" ); | |||
| addDirJars( antLoader, optionalDir ); | |||
| Properties launchProperties = new Properties(); | |||
| launchProperties.put( "ant.home", antHome.getAbsolutePath() ); | |||
| try | |||
| { | |||
| Class mainClass = antLoader.loadClass( "org.apache.tools.ant.Main" ); | |||
| antLoader.initializeClass( mainClass ); | |||
| final Class[] param = {Class.forName( "[Ljava.lang.String;" ), | |||
| Properties.class, ClassLoader.class}; | |||
| final Method startMethod = mainClass.getMethod( "start", param ); | |||
| final Object[] argument = {args, launchProperties, systemClassLoader}; | |||
| startMethod.invoke( null, argument ); | |||
| } | |||
| catch( Exception e ) | |||
| { | |||
| System.out.println( "Exception running Ant: " + e.getClass().getName() + ": " + e.getMessage() ); | |||
| e.printStackTrace(); | |||
| } | |||
| } | |||
| private static void addDirJars( AntClassLoader classLoader, File jarDir ) | |||
| { | |||
| String[] fileList = jarDir.list( | |||
| new FilenameFilter() | |||
| { | |||
| public boolean accept( File dir, String name ) | |||
| { | |||
| return name.endsWith( ".jar" ); | |||
| } | |||
| } ); | |||
| if( fileList != null ) | |||
| { | |||
| for( int i = 0; i < fileList.length; ++i ) | |||
| { | |||
| File jarFile = new File( jarDir, fileList[i] ); | |||
| classLoader.addPathElement( jarFile.getAbsolutePath() ); | |||
| } | |||
| } | |||
| } | |||
| private static void addToolsJar( AntClassLoader antLoader ) | |||
| { | |||
| String javaHome = System.getProperty( "java.home" ); | |||
| if( javaHome.endsWith( "jre" ) ) | |||
| { | |||
| javaHome = javaHome.substring( 0, javaHome.length() - 4 ); | |||
| } | |||
| System.out.println( "Java home is " + javaHome ); | |||
| File toolsJar = new File( javaHome, "lib/tools.jar" ); | |||
| if( !toolsJar.exists() ) | |||
| { | |||
| System.out.println( "Unable to find tools.jar at " + toolsJar.getPath() ); | |||
| } | |||
| else | |||
| { | |||
| antLoader.addPathElement( toolsJar.getAbsolutePath() ); | |||
| } | |||
| } | |||
| private static File determineAntHome( ClassLoader systemClassLoader ) | |||
| { | |||
| try | |||
| { | |||
| String className = Launcher.class.getName().replace( '.', '/' ) + ".class"; | |||
| URL classResource = systemClassLoader.getResource( className ); | |||
| String fileComponent = classResource.getFile(); | |||
| if( classResource.getProtocol().equals( "file" ) ) | |||
| { | |||
| // Class comes from a directory of class files rather than | |||
| // from a jar. | |||
| int classFileIndex = fileComponent.lastIndexOf( className ); | |||
| if( classFileIndex != -1 ) | |||
| { | |||
| fileComponent = fileComponent.substring( 0, classFileIndex ); | |||
| } | |||
| File classFilesDir = new File( fileComponent ); | |||
| File buildDir = new File( classFilesDir.getParent() ); | |||
| File devAntHome = new File( buildDir.getParent() ); | |||
| return devAntHome; | |||
| } | |||
| else if( classResource.getProtocol().equals( "jar" ) ) | |||
| { | |||
| // Class is coming from a jar. The file component of the URL | |||
| // is actually the URL of the jar file | |||
| int classSeparatorIndex = fileComponent.lastIndexOf( "!" ); | |||
| if( classSeparatorIndex != -1 ) | |||
| { | |||
| fileComponent = fileComponent.substring( 0, classSeparatorIndex ); | |||
| } | |||
| URL antJarURL = new URL( fileComponent ); | |||
| File antJarFile = new File( antJarURL.getFile() ); | |||
| File libDirectory = new File( antJarFile.getParent() ); | |||
| File antHome = new File( libDirectory.getParent() ); | |||
| return antHome; | |||
| } | |||
| } | |||
| catch( MalformedURLException e ) | |||
| { | |||
| e.printStackTrace(); | |||
| } | |||
| return null; | |||
| } | |||
| private static File determineAntHome11() | |||
| { | |||
| String classpath = System.getProperty( "java.class.path" ); | |||
| StringTokenizer tokenizer = new StringTokenizer( classpath, System.getProperty( "path.separator" ) ); | |||
| while( tokenizer.hasMoreTokens() ) | |||
| { | |||
| String path = tokenizer.nextToken(); | |||
| if( path.endsWith( "ant.jar" ) ) | |||
| { | |||
| File antJarFile = new File( path ); | |||
| File libDirectory = new File( antJarFile.getParent() ); | |||
| File antHome = new File( libDirectory.getParent() ); | |||
| return antHome; | |||
| } | |||
| } | |||
| return null; | |||
| } | |||
| } | |||
| @@ -0,0 +1,80 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant; | |||
| /** | |||
| * Stores the file name and line number in a file. | |||
| * | |||
| * @author RT | |||
| */ | |||
| public class Location | |||
| { | |||
| public final static Location UNKNOWN_LOCATION = new Location(); | |||
| private int columnNumber; | |||
| private String fileName; | |||
| private int lineNumber; | |||
| /** | |||
| * Creates a location consisting of a file name but no line number. | |||
| * | |||
| * @param fileName Description of Parameter | |||
| */ | |||
| public Location( String fileName ) | |||
| { | |||
| this( fileName, 0, 0 ); | |||
| } | |||
| /** | |||
| * Creates a location consisting of a file name and line number. | |||
| * | |||
| * @param fileName Description of Parameter | |||
| * @param lineNumber Description of Parameter | |||
| * @param columnNumber Description of Parameter | |||
| */ | |||
| public Location( String fileName, int lineNumber, int columnNumber ) | |||
| { | |||
| this.fileName = fileName; | |||
| this.lineNumber = lineNumber; | |||
| this.columnNumber = columnNumber; | |||
| } | |||
| /** | |||
| * Creates an "unknown" location. | |||
| */ | |||
| private Location() | |||
| { | |||
| this( null, 0, 0 ); | |||
| } | |||
| /** | |||
| * Returns the file name, line number and a trailing space. An error message | |||
| * can be appended easily. For unknown locations, returns an empty string. | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public String toString() | |||
| { | |||
| StringBuffer buf = new StringBuffer(); | |||
| if( fileName != null ) | |||
| { | |||
| buf.append( fileName ); | |||
| if( lineNumber != 0 ) | |||
| { | |||
| buf.append( ":" ); | |||
| buf.append( lineNumber ); | |||
| } | |||
| buf.append( ": " ); | |||
| } | |||
| return buf.toString(); | |||
| } | |||
| } | |||
| @@ -0,0 +1,842 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant; | |||
| import java.io.File; | |||
| import java.io.FileOutputStream; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.io.PrintStream; | |||
| import java.util.Enumeration; | |||
| import java.util.Properties; | |||
| import java.util.Vector; | |||
| /** | |||
| * Command line entry point into Ant. This class is entered via the cannonical | |||
| * `public static void main` entry point and reads the command line arguments. | |||
| * It then assembles and executes an Ant project. <p> | |||
| * | |||
| * If you integrating Ant into some other tool, this is not the class to use as | |||
| * an entry point. Please see the source code of this class to see how it | |||
| * manipulates the Ant project classes. | |||
| * | |||
| * @author duncan@x180.com | |||
| */ | |||
| public class Main | |||
| { | |||
| /** | |||
| * The default build file name | |||
| */ | |||
| public final static String DEFAULT_BUILD_FILENAME = "build.xml"; | |||
| private static String antVersion = null; | |||
| /** | |||
| * Our current message output status. Follows Project.MSG_XXX | |||
| */ | |||
| private int msgOutputLevel = Project.MSG_INFO; | |||
| /** | |||
| * null | |||
| */ | |||
| /** | |||
| * Stream that we are using for logging | |||
| */ | |||
| private PrintStream out = System.out; | |||
| /** | |||
| * Stream that we are using for logging error messages | |||
| */ | |||
| private PrintStream err = System.err; | |||
| /** | |||
| * The build targets | |||
| */ | |||
| private Vector targets = new Vector( 5 ); | |||
| /** | |||
| * Set of properties that can be used by tasks | |||
| */ | |||
| private Properties definedProps = new Properties(); | |||
| /** | |||
| * Names of classes to add as listeners to project | |||
| */ | |||
| private Vector listeners = new Vector( 5 ); | |||
| /** | |||
| * The Ant logger class. There may be only one logger. It will have the | |||
| * right to use the 'out' PrintStream. The class must implements the | |||
| * BuildLogger interface | |||
| */ | |||
| private String loggerClassname = null; | |||
| /** | |||
| * Indicates whether output to the log is to be unadorned. | |||
| */ | |||
| private boolean emacsMode = false; | |||
| /** | |||
| * Indicates if this ant should be run. | |||
| */ | |||
| private boolean readyToRun = false; | |||
| /** | |||
| * Indicates we should only parse and display the project help information | |||
| */ | |||
| private boolean projectHelp = false; | |||
| /** | |||
| * File that we are using for configuration | |||
| */ | |||
| private File buildFile; | |||
| protected Main( String[] args ) | |||
| throws BuildException | |||
| { | |||
| String searchForThis = null; | |||
| // cycle through given args | |||
| for( int i = 0; i < args.length; i++ ) | |||
| { | |||
| String arg = args[i]; | |||
| if( arg.equals( "-help" ) ) | |||
| { | |||
| printUsage(); | |||
| return; | |||
| } | |||
| else if( arg.equals( "-version" ) ) | |||
| { | |||
| printVersion(); | |||
| return; | |||
| } | |||
| else if( arg.equals( "-quiet" ) || arg.equals( "-q" ) ) | |||
| { | |||
| msgOutputLevel = Project.MSG_WARN; | |||
| } | |||
| else if( arg.equals( "-verbose" ) || arg.equals( "-v" ) ) | |||
| { | |||
| printVersion(); | |||
| msgOutputLevel = Project.MSG_VERBOSE; | |||
| } | |||
| else if( arg.equals( "-debug" ) ) | |||
| { | |||
| printVersion(); | |||
| msgOutputLevel = Project.MSG_DEBUG; | |||
| } | |||
| else if( arg.equals( "-logfile" ) || arg.equals( "-l" ) ) | |||
| { | |||
| try | |||
| { | |||
| File logFile = new File( args[i + 1] ); | |||
| i++; | |||
| out = new PrintStream( new FileOutputStream( logFile ) ); | |||
| err = out; | |||
| System.setOut( out ); | |||
| System.setErr( out ); | |||
| } | |||
| catch( IOException ioe ) | |||
| { | |||
| String msg = "Cannot write on the specified log file. " + | |||
| "Make sure the path exists and you have write permissions."; | |||
| System.out.println( msg ); | |||
| return; | |||
| } | |||
| catch( ArrayIndexOutOfBoundsException aioobe ) | |||
| { | |||
| String msg = "You must specify a log file when " + | |||
| "using the -log argument"; | |||
| System.out.println( msg ); | |||
| return; | |||
| } | |||
| } | |||
| else if( arg.equals( "-buildfile" ) || arg.equals( "-file" ) || arg.equals( "-f" ) ) | |||
| { | |||
| try | |||
| { | |||
| buildFile = new File( args[i + 1] ); | |||
| i++; | |||
| } | |||
| catch( ArrayIndexOutOfBoundsException aioobe ) | |||
| { | |||
| String msg = "You must specify a buildfile when " + | |||
| "using the -buildfile argument"; | |||
| System.out.println( msg ); | |||
| return; | |||
| } | |||
| } | |||
| else if( arg.equals( "-listener" ) ) | |||
| { | |||
| try | |||
| { | |||
| listeners.addElement( args[i + 1] ); | |||
| i++; | |||
| } | |||
| catch( ArrayIndexOutOfBoundsException aioobe ) | |||
| { | |||
| String msg = "You must specify a classname when " + | |||
| "using the -listener argument"; | |||
| System.out.println( msg ); | |||
| return; | |||
| } | |||
| } | |||
| else if( arg.startsWith( "-D" ) ) | |||
| { | |||
| /* | |||
| * Interestingly enough, we get to here when a user | |||
| * uses -Dname=value. However, in some cases, the JDK | |||
| * goes ahead * and parses this out to args | |||
| * {"-Dname", "value"} | |||
| * so instead of parsing on "=", we just make the "-D" | |||
| * characters go away and skip one argument forward. | |||
| * | |||
| * I don't know how to predict when the JDK is going | |||
| * to help or not, so we simply look for the equals sign. | |||
| */ | |||
| String name = arg.substring( 2, arg.length() ); | |||
| String value = null; | |||
| int posEq = name.indexOf( "=" ); | |||
| if( posEq > 0 ) | |||
| { | |||
| value = name.substring( posEq + 1 ); | |||
| name = name.substring( 0, posEq ); | |||
| } | |||
| else if( i < args.length - 1 ) | |||
| value = args[++i]; | |||
| definedProps.put( name, value ); | |||
| } | |||
| else if( arg.equals( "-logger" ) ) | |||
| { | |||
| if( loggerClassname != null ) | |||
| { | |||
| System.out.println( "Only one logger class may be specified." ); | |||
| return; | |||
| } | |||
| try | |||
| { | |||
| loggerClassname = args[++i]; | |||
| } | |||
| catch( ArrayIndexOutOfBoundsException aioobe ) | |||
| { | |||
| System.out.println( "You must specify a classname when " + | |||
| "using the -logger argument" ); | |||
| return; | |||
| } | |||
| } | |||
| else if( arg.equals( "-emacs" ) ) | |||
| { | |||
| emacsMode = true; | |||
| } | |||
| else if( arg.equals( "-projecthelp" ) ) | |||
| { | |||
| // set the flag to display the targets and quit | |||
| projectHelp = true; | |||
| } | |||
| else if( arg.equals( "-find" ) ) | |||
| { | |||
| // eat up next arg if present, default to build.xml | |||
| if( i < args.length - 1 ) | |||
| { | |||
| searchForThis = args[++i]; | |||
| } | |||
| else | |||
| { | |||
| searchForThis = DEFAULT_BUILD_FILENAME; | |||
| } | |||
| } | |||
| else if( arg.startsWith( "-" ) ) | |||
| { | |||
| // we don't have any more args to recognize! | |||
| String msg = "Unknown argument: " + arg; | |||
| System.out.println( msg ); | |||
| printUsage(); | |||
| return; | |||
| } | |||
| else | |||
| { | |||
| // if it's no other arg, it may be the target | |||
| targets.addElement( arg ); | |||
| } | |||
| } | |||
| // if buildFile was not specified on the command line, | |||
| if( buildFile == null ) | |||
| { | |||
| // but -find then search for it | |||
| if( searchForThis != null ) | |||
| { | |||
| buildFile = findBuildFile( System.getProperty( "user.dir" ), | |||
| searchForThis ); | |||
| } | |||
| else | |||
| { | |||
| buildFile = new File( DEFAULT_BUILD_FILENAME ); | |||
| } | |||
| } | |||
| // make sure buildfile exists | |||
| if( !buildFile.exists() ) | |||
| { | |||
| System.out.println( "Buildfile: " + buildFile + " does not exist!" ); | |||
| throw new BuildException( "Build failed" ); | |||
| } | |||
| // make sure it's not a directory (this falls into the ultra | |||
| // paranoid lets check everything catagory | |||
| if( buildFile.isDirectory() ) | |||
| { | |||
| System.out.println( "What? Buildfile: " + buildFile + " is a dir!" ); | |||
| throw new BuildException( "Build failed" ); | |||
| } | |||
| readyToRun = true; | |||
| } | |||
| public static synchronized String getAntVersion() | |||
| throws BuildException | |||
| { | |||
| if( antVersion == null ) | |||
| { | |||
| try | |||
| { | |||
| Properties props = new Properties(); | |||
| 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( "Apache Ant version " ); | |||
| msg.append( props.getProperty( "VERSION" ) ); | |||
| msg.append( " compiled on " ); | |||
| msg.append( props.getProperty( "DATE" ) ); | |||
| antVersion = msg.toString(); | |||
| } | |||
| catch( IOException ioe ) | |||
| { | |||
| throw new BuildException( "Could not load the version information:" | |||
| + ioe.getMessage() ); | |||
| } | |||
| catch( NullPointerException npe ) | |||
| { | |||
| throw new BuildException( "Could not load the version information." ); | |||
| } | |||
| } | |||
| return antVersion; | |||
| } | |||
| /** | |||
| * Command line entry point. This method kicks off the building of a project | |||
| * object and executes a build using either a given target or the default | |||
| * target. | |||
| * | |||
| * @param args Command line args. | |||
| */ | |||
| public static void main( String[] args ) | |||
| { | |||
| start( args, null, null ); | |||
| } | |||
| /** | |||
| * Entry point method. | |||
| * | |||
| * @param args Description of Parameter | |||
| * @param additionalUserProperties Description of Parameter | |||
| * @param coreLoader Description of Parameter | |||
| */ | |||
| public static void start( String[] args, Properties additionalUserProperties, | |||
| ClassLoader coreLoader ) | |||
| { | |||
| Main m = null; | |||
| try | |||
| { | |||
| m = new Main( args ); | |||
| } | |||
| catch( Throwable exc ) | |||
| { | |||
| printMessage( exc ); | |||
| System.exit( 1 ); | |||
| } | |||
| if( additionalUserProperties != null ) | |||
| { | |||
| for( Enumeration e = additionalUserProperties.keys(); e.hasMoreElements(); ) | |||
| { | |||
| String key = ( String )e.nextElement(); | |||
| String property = additionalUserProperties.getProperty( key ); | |||
| m.definedProps.put( key, property ); | |||
| } | |||
| } | |||
| try | |||
| { | |||
| m.runBuild( coreLoader ); | |||
| System.exit( 0 ); | |||
| } | |||
| catch( BuildException be ) | |||
| { | |||
| if( m.err != System.err ) | |||
| { | |||
| printMessage( be ); | |||
| } | |||
| System.exit( 1 ); | |||
| } | |||
| catch( Throwable exc ) | |||
| { | |||
| exc.printStackTrace(); | |||
| printMessage( exc ); | |||
| System.exit( 1 ); | |||
| } | |||
| } | |||
| /** | |||
| * Search for the insert position to keep names a sorted list of Strings | |||
| * | |||
| * @param names Description of Parameter | |||
| * @param name Description of Parameter | |||
| * @return Description of the Returned Value | |||
| */ | |||
| private static int findTargetPosition( Vector names, String name ) | |||
| { | |||
| int res = names.size(); | |||
| for( int i = 0; i < names.size() && res == names.size(); i++ ) | |||
| { | |||
| if( name.compareTo( ( String )names.elementAt( i ) ) < 0 ) | |||
| { | |||
| res = i; | |||
| } | |||
| } | |||
| return res; | |||
| } | |||
| /** | |||
| * Print the project description, if any | |||
| * | |||
| * @param project Description of Parameter | |||
| */ | |||
| private static void printDescription( Project project ) | |||
| { | |||
| if( project.getDescription() != null ) | |||
| { | |||
| System.out.println( project.getDescription() ); | |||
| } | |||
| } | |||
| /** | |||
| * Prints the message of the Throwable if it's not null. | |||
| * | |||
| * @param t Description of Parameter | |||
| */ | |||
| private static void printMessage( Throwable t ) | |||
| { | |||
| String message = t.getMessage(); | |||
| if( message != null ) | |||
| { | |||
| System.err.println( message ); | |||
| } | |||
| } | |||
| /** | |||
| * Print out a list of all targets in the current buildfile | |||
| * | |||
| * @param project Description of Parameter | |||
| * @param printSubTargets Description of Parameter | |||
| */ | |||
| private static void printTargets( Project project, boolean printSubTargets ) | |||
| { | |||
| // find the target with the longest name | |||
| int maxLength = 0; | |||
| Enumeration ptargets = project.getTargets().elements(); | |||
| String targetName; | |||
| String targetDescription; | |||
| Target currentTarget; | |||
| // split the targets in top-level and sub-targets depending | |||
| // on the presence of a description | |||
| Vector topNames = new Vector(); | |||
| Vector topDescriptions = new Vector(); | |||
| Vector subNames = new Vector(); | |||
| while( ptargets.hasMoreElements() ) | |||
| { | |||
| currentTarget = ( Target )ptargets.nextElement(); | |||
| targetName = currentTarget.getName(); | |||
| targetDescription = currentTarget.getDescription(); | |||
| // maintain a sorted list of targets | |||
| if( targetDescription == null ) | |||
| { | |||
| int pos = findTargetPosition( subNames, targetName ); | |||
| subNames.insertElementAt( targetName, pos ); | |||
| } | |||
| else | |||
| { | |||
| int pos = findTargetPosition( topNames, targetName ); | |||
| topNames.insertElementAt( targetName, pos ); | |||
| topDescriptions.insertElementAt( targetDescription, pos ); | |||
| if( targetName.length() > maxLength ) | |||
| { | |||
| maxLength = targetName.length(); | |||
| } | |||
| } | |||
| } | |||
| printTargets( topNames, topDescriptions, "Main targets:", maxLength ); | |||
| if( printSubTargets ) | |||
| { | |||
| printTargets( subNames, null, "Subtargets:", 0 ); | |||
| } | |||
| String defaultTarget = project.getDefaultTarget(); | |||
| if( defaultTarget != null && !"".equals( defaultTarget ) ) | |||
| {// shouldn't need to check but... | |||
| System.out.println( "Default target: " + defaultTarget ); | |||
| } | |||
| } | |||
| /** | |||
| * Output a formatted list of target names with an optional description | |||
| * | |||
| * @param names Description of Parameter | |||
| * @param descriptions Description of Parameter | |||
| * @param heading Description of Parameter | |||
| * @param maxlen Description of Parameter | |||
| */ | |||
| private static void printTargets( Vector names, Vector descriptions, String heading, int maxlen ) | |||
| { | |||
| // now, start printing the targets and their descriptions | |||
| String lSep = System.getProperty( "line.separator" ); | |||
| // got a bit annoyed that I couldn't find a pad function | |||
| String spaces = " "; | |||
| while( spaces.length() < maxlen ) | |||
| { | |||
| spaces += spaces; | |||
| } | |||
| StringBuffer msg = new StringBuffer(); | |||
| msg.append( heading + lSep + lSep ); | |||
| for( int i = 0; i < names.size(); i++ ) | |||
| { | |||
| msg.append( " " ); | |||
| msg.append( names.elementAt( i ) ); | |||
| if( descriptions != null ) | |||
| { | |||
| msg.append( spaces.substring( 0, maxlen - ( ( String )names.elementAt( i ) ).length() + 2 ) ); | |||
| msg.append( descriptions.elementAt( i ) ); | |||
| } | |||
| msg.append( lSep ); | |||
| } | |||
| System.out.println( msg.toString() ); | |||
| } | |||
| /** | |||
| * Prints the usage of how to use this class to System.out | |||
| */ | |||
| private static void printUsage() | |||
| { | |||
| String lSep = System.getProperty( "line.separator" ); | |||
| StringBuffer msg = new StringBuffer(); | |||
| msg.append( "ant [options] [target [target2 [target3] ...]]" + lSep ); | |||
| msg.append( "Options: " + lSep ); | |||
| msg.append( " -help print this message" + lSep ); | |||
| msg.append( " -projecthelp print project help information" + lSep ); | |||
| msg.append( " -version print the version information and exit" + lSep ); | |||
| msg.append( " -quiet be extra quiet" + lSep ); | |||
| msg.append( " -verbose be extra verbose" + lSep ); | |||
| msg.append( " -debug print debugging information" + lSep ); | |||
| msg.append( " -emacs produce logging information without adornments" + lSep ); | |||
| msg.append( " -logfile <file> use given file for log" + lSep ); | |||
| msg.append( " -logger <classname> the class which is to perform logging" + lSep ); | |||
| msg.append( " -listener <classname> add an instance of class as a project listener" + lSep ); | |||
| msg.append( " -buildfile <file> use given buildfile" + lSep ); | |||
| msg.append( " -D<property>=<value> use value for given property" + lSep ); | |||
| msg.append( " -find <file> search for buildfile towards the root of the" + lSep ); | |||
| msg.append( " filesystem and use it" + lSep ); | |||
| System.out.println( msg.toString() ); | |||
| } | |||
| private static void printVersion() | |||
| throws BuildException | |||
| { | |||
| System.out.println( getAntVersion() ); | |||
| } | |||
| protected void addBuildListeners( Project project ) | |||
| { | |||
| // Add the default listener | |||
| project.addBuildListener( createLogger() ); | |||
| for( int i = 0; i < listeners.size(); i++ ) | |||
| { | |||
| String className = ( String )listeners.elementAt( i ); | |||
| try | |||
| { | |||
| BuildListener listener = | |||
| ( BuildListener )Class.forName( className ).newInstance(); | |||
| project.addBuildListener( listener ); | |||
| } | |||
| catch( Throwable exc ) | |||
| { | |||
| throw new BuildException( "Unable to instantiate listener " + className, exc ); | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Helper to get the parent file for a given file. <P> | |||
| * | |||
| * Added to simulate File.getParentFile() from JDK 1.2. | |||
| * | |||
| * @param file File | |||
| * @return Parent file or null if none | |||
| */ | |||
| private File getParentFile( File file ) | |||
| { | |||
| String filename = file.getAbsolutePath(); | |||
| file = new File( filename ); | |||
| filename = file.getParent(); | |||
| if( filename != null && msgOutputLevel >= Project.MSG_VERBOSE ) | |||
| { | |||
| System.out.println( "Searching in " + filename ); | |||
| } | |||
| return ( filename == null ) ? null : new File( filename ); | |||
| } | |||
| /** | |||
| * Creates the default build logger for sending build events to the ant log. | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| private BuildLogger createLogger() | |||
| { | |||
| BuildLogger logger = null; | |||
| if( loggerClassname != null ) | |||
| { | |||
| try | |||
| { | |||
| logger = ( BuildLogger )( Class.forName( loggerClassname ).newInstance() ); | |||
| } | |||
| catch( ClassCastException e ) | |||
| { | |||
| System.err.println( "The specified logger class " + loggerClassname + | |||
| " does not implement the BuildLogger interface" ); | |||
| throw new RuntimeException(); | |||
| } | |||
| catch( Exception e ) | |||
| { | |||
| System.err.println( "Unable to instantiate specified logger class " + | |||
| loggerClassname + " : " + e.getClass().getName() ); | |||
| throw new RuntimeException(); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| logger = new DefaultLogger(); | |||
| } | |||
| logger.setMessageOutputLevel( msgOutputLevel ); | |||
| logger.setOutputPrintStream( out ); | |||
| logger.setErrorPrintStream( err ); | |||
| logger.setEmacsMode( emacsMode ); | |||
| return logger; | |||
| } | |||
| /** | |||
| * Search parent directories for the build file. <P> | |||
| * | |||
| * Takes the given target as a suffix to append to each parent directory in | |||
| * seach of a build file. Once the root of the file-system has been reached | |||
| * an exception is thrown. | |||
| * | |||
| * @param suffix Suffix filename to look for in parents. | |||
| * @param start Description of Parameter | |||
| * @return A handle to the build file | |||
| * @exception BuildException Failed to locate a build file | |||
| */ | |||
| private File findBuildFile( String start, String suffix ) | |||
| throws BuildException | |||
| { | |||
| if( msgOutputLevel >= Project.MSG_INFO ) | |||
| { | |||
| System.out.println( "Searching for " + suffix + " ..." ); | |||
| } | |||
| File parent = new File( new File( start ).getAbsolutePath() ); | |||
| File file = new File( parent, suffix ); | |||
| // check if the target file exists in the current directory | |||
| while( !file.exists() ) | |||
| { | |||
| // change to parent directory | |||
| parent = getParentFile( parent ); | |||
| // if parent is null, then we are at the root of the fs, | |||
| // complain that we can't find the build file. | |||
| if( parent == null ) | |||
| { | |||
| throw new BuildException( "Could not locate a build file!" ); | |||
| } | |||
| // refresh our file handle | |||
| file = new File( parent, suffix ); | |||
| } | |||
| return file; | |||
| } | |||
| /** | |||
| * Executes the build. | |||
| * | |||
| * @param coreLoader Description of Parameter | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| private void runBuild( ClassLoader coreLoader ) | |||
| throws BuildException | |||
| { | |||
| if( !readyToRun ) | |||
| { | |||
| return; | |||
| } | |||
| // track when we started | |||
| if( msgOutputLevel >= Project.MSG_INFO ) | |||
| { | |||
| System.out.println( "Buildfile: " + buildFile ); | |||
| } | |||
| final Project project = new Project(); | |||
| project.setCoreLoader( coreLoader ); | |||
| Throwable error = null; | |||
| try | |||
| { | |||
| addBuildListeners( project ); | |||
| PrintStream err = System.err; | |||
| PrintStream out = System.out; | |||
| // use a system manager that prevents from System.exit() | |||
| // only in JDK > 1.1 | |||
| SecurityManager oldsm = null; | |||
| if( !Project.JAVA_1_0.equals( Project.getJavaVersion() ) && | |||
| !Project.JAVA_1_1.equals( Project.getJavaVersion() ) ) | |||
| { | |||
| oldsm = System.getSecurityManager(); | |||
| //SecurityManager can not be installed here for backwards | |||
| //compatability reasons (PD). Needs to be loaded prior to | |||
| //ant class if we are going to implement it. | |||
| //System.setSecurityManager(new NoExitSecurityManager()); | |||
| } | |||
| try | |||
| { | |||
| System.setOut( new PrintStream( new DemuxOutputStream( project, false ) ) ); | |||
| System.setErr( new PrintStream( new DemuxOutputStream( project, true ) ) ); | |||
| if( !projectHelp ) | |||
| { | |||
| project.fireBuildStarted(); | |||
| } | |||
| project.init(); | |||
| project.setUserProperty( "ant.version", getAntVersion() ); | |||
| // 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. | |||
| String noParserMessage = | |||
| "No JAXP compliant XML parser found. Please visit http://xml.apache.org for a suitable parser"; | |||
| try | |||
| { | |||
| Class.forName( "javax.xml.parsers.SAXParserFactory" ); | |||
| ProjectHelper.configureProject( project, buildFile ); | |||
| } | |||
| catch( NoClassDefFoundError ncdfe ) | |||
| { | |||
| throw new BuildException( noParserMessage, ncdfe ); | |||
| } | |||
| catch( ClassNotFoundException cnfe ) | |||
| { | |||
| throw new BuildException( noParserMessage, cnfe ); | |||
| } | |||
| catch( NullPointerException npe ) | |||
| { | |||
| throw new BuildException( noParserMessage, npe ); | |||
| } | |||
| if( projectHelp ) | |||
| { | |||
| printDescription( project ); | |||
| printTargets( project, msgOutputLevel > Project.MSG_INFO ); | |||
| return; | |||
| } | |||
| // make sure that we have a target to execute | |||
| if( targets.size() == 0 ) | |||
| { | |||
| targets.addElement( project.getDefaultTarget() ); | |||
| } | |||
| project.executeTargets( targets ); | |||
| } | |||
| finally | |||
| { | |||
| // put back the original security manager | |||
| //The following will never eval to true. (PD) | |||
| if( oldsm != null ) | |||
| { | |||
| System.setSecurityManager( oldsm ); | |||
| } | |||
| System.setOut( out ); | |||
| System.setErr( err ); | |||
| } | |||
| } | |||
| catch( RuntimeException exc ) | |||
| { | |||
| error = exc; | |||
| throw exc; | |||
| } | |||
| catch( Error err ) | |||
| { | |||
| error = err; | |||
| throw err; | |||
| } | |||
| finally | |||
| { | |||
| if( !projectHelp ) | |||
| { | |||
| project.fireBuildFinished( error ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,50 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant; | |||
| /** | |||
| * Extends DefaultLogger to strip out empty targets. | |||
| * | |||
| * @author <a href="mailto:donaldp@apache.org">Peter Donald</a> | |||
| */ | |||
| public class NoBannerLogger extends DefaultLogger | |||
| { | |||
| private final static String lSep = System.getProperty( "line.separator" ); | |||
| protected String targetName; | |||
| public void messageLogged( BuildEvent event ) | |||
| { | |||
| if( event.getPriority() > msgOutputLevel || | |||
| null == event.getMessage() || | |||
| "".equals( event.getMessage().trim() ) ) | |||
| { | |||
| return; | |||
| } | |||
| if( null != targetName ) | |||
| { | |||
| out.println( lSep + targetName + ":" ); | |||
| targetName = null; | |||
| } | |||
| super.messageLogged( event ); | |||
| } | |||
| public void targetFinished( BuildEvent event ) | |||
| { | |||
| targetName = null; | |||
| } | |||
| public void targetStarted( BuildEvent event ) | |||
| { | |||
| targetName = event.getTarget().getName(); | |||
| } | |||
| } | |||
| @@ -0,0 +1,90 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant; | |||
| import java.io.File; | |||
| import java.util.NoSuchElementException; | |||
| import java.util.StringTokenizer; | |||
| /** | |||
| * A Path tokenizer takes a path and returns the components that make up that | |||
| * path. The path can use path separators of either ':' or ';' and file | |||
| * separators of either '/' or '\' | |||
| * | |||
| * @author Conor MacNeill (conor@ieee.org) | |||
| */ | |||
| public class PathTokenizer | |||
| { | |||
| /** | |||
| * A String which stores any path components which have been read ahead. | |||
| */ | |||
| private String lookahead = null; | |||
| /** | |||
| * Flag to indicate whether we are running on a platform with a DOS style | |||
| * filesystem | |||
| */ | |||
| private boolean dosStyleFilesystem; | |||
| /** | |||
| * A tokenizer to break the string up based on the ':' or ';' separators. | |||
| */ | |||
| private StringTokenizer tokenizer; | |||
| public PathTokenizer( String path ) | |||
| { | |||
| tokenizer = new StringTokenizer( path, ":;", false ); | |||
| dosStyleFilesystem = File.pathSeparatorChar == ';'; | |||
| } | |||
| public boolean hasMoreTokens() | |||
| { | |||
| if( lookahead != null ) | |||
| { | |||
| return true; | |||
| } | |||
| return tokenizer.hasMoreTokens(); | |||
| } | |||
| public String nextToken() | |||
| throws NoSuchElementException | |||
| { | |||
| String token = null; | |||
| if( lookahead != null ) | |||
| { | |||
| token = lookahead; | |||
| lookahead = null; | |||
| } | |||
| else | |||
| { | |||
| token = tokenizer.nextToken().trim(); | |||
| } | |||
| if( token.length() == 1 && Character.isLetter( token.charAt( 0 ) ) | |||
| && dosStyleFilesystem | |||
| && tokenizer.hasMoreTokens() ) | |||
| { | |||
| // we are on a dos style system so this path could be a drive | |||
| // spec. We look at the next token | |||
| String nextToken = tokenizer.nextToken().trim(); | |||
| if( nextToken.startsWith( "\\" ) || nextToken.startsWith( "/" ) ) | |||
| { | |||
| // we know we are on a DOS style platform and the next path starts with a | |||
| // slash or backslash, so we know this is a drive spec | |||
| token += ":" + nextToken; | |||
| } | |||
| else | |||
| { | |||
| // store the token just read for next time | |||
| lookahead = nextToken; | |||
| } | |||
| } | |||
| return token; | |||
| } | |||
| } | |||
| @@ -0,0 +1,71 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant; | |||
| import org.apache.myrmidon.api.AbstractTask; | |||
| /** | |||
| * Base class for components of a project, including tasks and data types. | |||
| * Provides common facilities. | |||
| * | |||
| * @author <a href="mailto:conor@apache.org">Conor MacNeill</a> | |||
| */ | |||
| public abstract class ProjectComponent | |||
| extends AbstractTask | |||
| { | |||
| protected Project project = null; | |||
| /** | |||
| * Sets the project object of this component. This method is used by project | |||
| * when a component is added to it so that the component has access to the | |||
| * functions of the project. It should not be used for any other purpose. | |||
| * | |||
| * @param project Project in whose scope this component belongs. | |||
| */ | |||
| public void setProject( Project project ) | |||
| { | |||
| this.project = project; | |||
| } | |||
| /** | |||
| * Get the Project to which this component belongs | |||
| * | |||
| * @return the components's project. | |||
| */ | |||
| public Project getProject() | |||
| { | |||
| return project; | |||
| } | |||
| /** | |||
| * Log a message with the default (INFO) priority. | |||
| * | |||
| * @param msg Description of Parameter | |||
| */ | |||
| public void log( String msg ) | |||
| { | |||
| log( msg, Project.MSG_INFO ); | |||
| } | |||
| /** | |||
| * Log a mesage with the give priority. | |||
| * | |||
| * @param msgLevel the message priority at which this message is to be | |||
| * logged. | |||
| * @param msg Description of Parameter | |||
| */ | |||
| public void log( String msg, int msgLevel ) | |||
| { | |||
| if( project != null ) | |||
| { | |||
| project.log( msg, msgLevel ); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,159 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant; | |||
| import java.util.Enumeration; | |||
| import java.util.Locale; | |||
| import java.util.Vector; | |||
| import org.xml.sax.AttributeList; | |||
| import org.xml.sax.helpers.AttributeListImpl; | |||
| /** | |||
| * Wrapper class that holds the attributes of a Task (or elements nested below | |||
| * that level) and takes care of configuring that element at runtime. | |||
| * | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| */ | |||
| public class RuntimeConfigurable | |||
| { | |||
| private String elementTag = null; | |||
| private Vector children = new Vector(); | |||
| private Object wrappedObject = null; | |||
| private StringBuffer characters = new StringBuffer(); | |||
| private AttributeList attributes; | |||
| /** | |||
| * @param proxy The element to wrap. | |||
| * @param elementTag Description of Parameter | |||
| */ | |||
| public RuntimeConfigurable( Object proxy, String elementTag ) | |||
| { | |||
| wrappedObject = proxy; | |||
| this.elementTag = elementTag; | |||
| } | |||
| /** | |||
| * Set's the attributes for the wrapped element. | |||
| * | |||
| * @param attributes The new Attributes value | |||
| */ | |||
| public void setAttributes( AttributeList attributes ) | |||
| { | |||
| this.attributes = new AttributeListImpl( attributes ); | |||
| } | |||
| /** | |||
| * Returns the AttributeList of the wrapped element. | |||
| * | |||
| * @return The Attributes value | |||
| */ | |||
| public AttributeList getAttributes() | |||
| { | |||
| return attributes; | |||
| } | |||
| public String getElementTag() | |||
| { | |||
| return elementTag; | |||
| } | |||
| /** | |||
| * Adds child elements to the wrapped element. | |||
| * | |||
| * @param child The feature to be added to the Child attribute | |||
| */ | |||
| public void addChild( RuntimeConfigurable child ) | |||
| { | |||
| children.addElement( child ); | |||
| } | |||
| /** | |||
| * Add characters from #PCDATA areas to the wrapped element. | |||
| * | |||
| * @param data The feature to be added to the Text attribute | |||
| */ | |||
| public void addText( String data ) | |||
| { | |||
| characters.append( data ); | |||
| } | |||
| /** | |||
| * Add characters from #PCDATA areas to the wrapped element. | |||
| * | |||
| * @param buf The feature to be added to the Text attribute | |||
| * @param start The feature to be added to the Text attribute | |||
| * @param end The feature to be added to the Text attribute | |||
| */ | |||
| public void addText( char[] buf, int start, int end ) | |||
| { | |||
| addText( new String( buf, start, end ) ); | |||
| } | |||
| /** | |||
| * Configure the wrapped element and all children. | |||
| * | |||
| * @param p Description of Parameter | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| public void maybeConfigure( Project p ) | |||
| throws BuildException | |||
| { | |||
| String id = null; | |||
| if( attributes != null ) | |||
| { | |||
| ProjectHelper.configure( wrappedObject, attributes, p ); | |||
| id = attributes.getValue( "id" ); | |||
| attributes = null; | |||
| } | |||
| if( characters.length() != 0 ) | |||
| { | |||
| ProjectHelper.addText( p, wrappedObject, characters.toString() ); | |||
| characters.setLength( 0 ); | |||
| } | |||
| Enumeration enum = children.elements(); | |||
| while( enum.hasMoreElements() ) | |||
| { | |||
| RuntimeConfigurable child = ( RuntimeConfigurable )enum.nextElement(); | |||
| if( child.wrappedObject instanceof Task ) | |||
| { | |||
| Task childTask = ( Task )child.wrappedObject; | |||
| childTask.setRuntimeConfigurableWrapper( child ); | |||
| childTask.maybeConfigure(); | |||
| } | |||
| else | |||
| { | |||
| child.maybeConfigure( p ); | |||
| } | |||
| ProjectHelper.storeChild( p, wrappedObject, child.wrappedObject, child.getElementTag().toLowerCase( Locale.US ) ); | |||
| } | |||
| if( id != null ) | |||
| { | |||
| p.addReference( id, wrappedObject ); | |||
| } | |||
| } | |||
| void setProxy( Object proxy ) | |||
| { | |||
| wrappedObject = proxy; | |||
| } | |||
| /** | |||
| * Returns the child with index <code>index</code>. | |||
| * | |||
| * @param index Description of Parameter | |||
| * @return The Child value | |||
| */ | |||
| RuntimeConfigurable getChild( int index ) | |||
| { | |||
| return ( RuntimeConfigurable )children.elementAt( index ); | |||
| } | |||
| } | |||
| @@ -0,0 +1,232 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant; | |||
| import java.util.Enumeration; | |||
| import java.util.StringTokenizer; | |||
| import java.util.Vector; | |||
| /** | |||
| * This class implements a target object with required parameters. | |||
| * | |||
| * @author James Davidson <a href="mailto:duncan@x180.com">duncan@x180.com</a> | |||
| */ | |||
| public class Target implements TaskContainer | |||
| { | |||
| private String ifCondition = ""; | |||
| private String unlessCondition = ""; | |||
| private Vector dependencies = new Vector( 2 ); | |||
| private Vector children = new Vector( 5 ); | |||
| private String description = null; | |||
| private String name; | |||
| private Project project; | |||
| public void setDepends( String depS ) | |||
| { | |||
| if( depS.length() > 0 ) | |||
| { | |||
| StringTokenizer tok = | |||
| new StringTokenizer( depS, ",", true ); | |||
| while( tok.hasMoreTokens() ) | |||
| { | |||
| String token = tok.nextToken().trim(); | |||
| //Make sure the dependency is not empty string | |||
| if( token.equals( "" ) || token.equals( "," ) ) | |||
| { | |||
| throw new BuildException( "Syntax Error: Depend attribute " + | |||
| "for target \"" + getName() + | |||
| "\" has an empty string for dependency." ); | |||
| } | |||
| addDependency( token ); | |||
| //Make sure that depends attribute does not | |||
| //end in a , | |||
| if( tok.hasMoreTokens() ) | |||
| { | |||
| token = tok.nextToken(); | |||
| if( !tok.hasMoreTokens() || !token.equals( "," ) ) | |||
| { | |||
| throw new BuildException( "Syntax Error: Depend attribute " + | |||
| "for target \"" + getName() + | |||
| "\" ends with a , character" ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| public void setDescription( String description ) | |||
| { | |||
| this.description = description; | |||
| } | |||
| public void setIf( String property ) | |||
| { | |||
| this.ifCondition = ( property == null ) ? "" : property; | |||
| } | |||
| public void setName( String name ) | |||
| { | |||
| this.name = name; | |||
| } | |||
| public void setProject( Project project ) | |||
| { | |||
| this.project = project; | |||
| } | |||
| public void setUnless( String property ) | |||
| { | |||
| this.unlessCondition = ( property == null ) ? "" : property; | |||
| } | |||
| public Enumeration getDependencies() | |||
| { | |||
| return dependencies.elements(); | |||
| } | |||
| public String getDescription() | |||
| { | |||
| return description; | |||
| } | |||
| public String getName() | |||
| { | |||
| return name; | |||
| } | |||
| public Project getProject() | |||
| { | |||
| return project; | |||
| } | |||
| /** | |||
| * Get the current set of tasks to be executed by this target. | |||
| * | |||
| * @return The current set of tasks. | |||
| */ | |||
| public Task[] getTasks() | |||
| { | |||
| Vector tasks = new Vector( children.size() ); | |||
| Enumeration enum = children.elements(); | |||
| while( enum.hasMoreElements() ) | |||
| { | |||
| Object o = enum.nextElement(); | |||
| if( o instanceof Task ) | |||
| { | |||
| tasks.addElement( o ); | |||
| } | |||
| } | |||
| Task[] retval = new Task[tasks.size()]; | |||
| tasks.copyInto( retval ); | |||
| return retval; | |||
| } | |||
| public final void performTasks() | |||
| { | |||
| try | |||
| { | |||
| project.fireTargetStarted( this ); | |||
| execute(); | |||
| project.fireTargetFinished( this, null ); | |||
| } | |||
| catch( RuntimeException exc ) | |||
| { | |||
| project.fireTargetFinished( this, exc ); | |||
| throw exc; | |||
| } | |||
| } | |||
| public void addDataType( RuntimeConfigurable r ) | |||
| { | |||
| children.addElement( r ); | |||
| } | |||
| public void addDependency( String dependency ) | |||
| { | |||
| dependencies.addElement( dependency ); | |||
| } | |||
| public void addTask( Task task ) | |||
| { | |||
| children.addElement( task ); | |||
| } | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| if( testIfCondition() && testUnlessCondition() ) | |||
| { | |||
| Enumeration enum = children.elements(); | |||
| while( enum.hasMoreElements() ) | |||
| { | |||
| Object o = enum.nextElement(); | |||
| if( o instanceof Task ) | |||
| { | |||
| Task task = ( Task )o; | |||
| task.perform(); | |||
| } | |||
| else | |||
| { | |||
| RuntimeConfigurable r = ( RuntimeConfigurable )o; | |||
| r.maybeConfigure( project ); | |||
| } | |||
| } | |||
| } | |||
| else if( !testIfCondition() ) | |||
| { | |||
| project.log( this, "Skipped because property '" + this.ifCondition + "' not set.", | |||
| Project.MSG_VERBOSE ); | |||
| } | |||
| else | |||
| { | |||
| project.log( this, "Skipped because property '" + this.unlessCondition + "' set.", | |||
| Project.MSG_VERBOSE ); | |||
| } | |||
| } | |||
| public String toString() | |||
| { | |||
| return name; | |||
| } | |||
| void replaceChild( Task el, Object o ) | |||
| { | |||
| int index = -1; | |||
| while( ( index = children.indexOf( el ) ) >= 0 ) | |||
| { | |||
| children.setElementAt( o, index ); | |||
| } | |||
| } | |||
| private boolean testIfCondition() | |||
| { | |||
| if( "".equals( ifCondition ) ) | |||
| { | |||
| return true; | |||
| } | |||
| String test = project.replaceProperties( ifCondition ); | |||
| return project.getProperty( test ) != null; | |||
| } | |||
| private boolean testUnlessCondition() | |||
| { | |||
| if( "".equals( unlessCondition ) ) | |||
| { | |||
| return true; | |||
| } | |||
| String test = project.replaceProperties( unlessCondition ); | |||
| return project.getProperty( test ) == null; | |||
| } | |||
| } | |||
| @@ -0,0 +1,281 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| public abstract class Task | |||
| extends ProjectComponent | |||
| implements org.apache.myrmidon.api.Task | |||
| { | |||
| protected Target target; | |||
| protected String description; | |||
| protected Location location = Location.UNKNOWN_LOCATION; | |||
| protected String taskName; | |||
| protected String taskType; | |||
| private boolean invalid; | |||
| protected RuntimeConfigurable wrapper; | |||
| private UnknownElement replacement; | |||
| /** | |||
| * Sets a description of the current action. It will be usefull in | |||
| * commenting what we are doing. | |||
| * | |||
| * @param desc The new Description value | |||
| */ | |||
| public void setDescription( String desc ) | |||
| { | |||
| description = desc; | |||
| } | |||
| /** | |||
| * Sets the file location where this task was defined. | |||
| * | |||
| * @param location The new Location value | |||
| */ | |||
| public void setLocation( Location location ) | |||
| { | |||
| this.location = location; | |||
| } | |||
| /** | |||
| * Sets the target object of this task. | |||
| * | |||
| * @param target Target in whose scope this task belongs. | |||
| */ | |||
| public void setOwningTarget( Target target ) | |||
| { | |||
| this.target = target; | |||
| } | |||
| /** | |||
| * Set the name to use in logging messages. | |||
| * | |||
| * @param name the name to use in logging messages. | |||
| */ | |||
| public void setTaskName( String name ) | |||
| { | |||
| this.taskName = name; | |||
| } | |||
| public String getDescription() | |||
| { | |||
| return description; | |||
| } | |||
| /** | |||
| * Returns the file location where this task was defined. | |||
| * | |||
| * @return The Location value | |||
| */ | |||
| public Location getLocation() | |||
| { | |||
| return location; | |||
| } | |||
| /** | |||
| * Get the Target to which this task belongs | |||
| * | |||
| * @return the task's target. | |||
| */ | |||
| public Target getOwningTarget() | |||
| { | |||
| return target; | |||
| } | |||
| /** | |||
| * Returns the wrapper class for runtime configuration. | |||
| * | |||
| * @return The RuntimeConfigurableWrapper value | |||
| */ | |||
| public RuntimeConfigurable getRuntimeConfigurableWrapper() | |||
| { | |||
| if( wrapper == null ) | |||
| { | |||
| wrapper = new RuntimeConfigurable( this, getTaskName() ); | |||
| } | |||
| return wrapper; | |||
| } | |||
| /** | |||
| * Get the name to use in logging messages. | |||
| * | |||
| * @return the name to use in logging messages. | |||
| */ | |||
| public String getTaskName() | |||
| { | |||
| return taskName; | |||
| } | |||
| /** | |||
| * Perform this task | |||
| */ | |||
| public final void perform() | |||
| throws TaskException | |||
| { | |||
| if( !invalid ) | |||
| { | |||
| try | |||
| { | |||
| project.fireTaskStarted( this ); | |||
| maybeConfigure(); | |||
| execute(); | |||
| project.fireTaskFinished( this, null ); | |||
| } | |||
| catch( TaskException te ) | |||
| { | |||
| if( te instanceof BuildException ) | |||
| { | |||
| BuildException be = (BuildException)te; | |||
| if( be.getLocation() == Location.UNKNOWN_LOCATION ) | |||
| { | |||
| be.setLocation( getLocation() ); | |||
| } | |||
| } | |||
| project.fireTaskFinished( this, te ); | |||
| throw te; | |||
| } | |||
| catch( RuntimeException re ) | |||
| { | |||
| project.fireTaskFinished( this, re ); | |||
| throw re; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| UnknownElement ue = getReplacement(); | |||
| Task task = ue.getTask(); | |||
| task.perform(); | |||
| } | |||
| } | |||
| /** | |||
| * Called by the project to let the task do it's work. This method may be | |||
| * called more than once, if the task is invoked more than once. For | |||
| * example, if target1 and target2 both depend on target3, then running "ant | |||
| * target1 target2" will run all tasks in target3 twice. | |||
| * | |||
| * @throws BuildException if someting goes wrong with the build | |||
| */ | |||
| public void execute() | |||
| throws TaskException | |||
| { | |||
| } | |||
| /** | |||
| * Called by the project to let the task initialize properly. | |||
| * | |||
| * @throws BuildException if someting goes wrong with the build | |||
| */ | |||
| public void init() | |||
| throws TaskException | |||
| { | |||
| } | |||
| /** | |||
| * Log a message with the default (INFO) priority. | |||
| * | |||
| * @param msg Description of Parameter | |||
| */ | |||
| public void log( String msg ) | |||
| { | |||
| log( msg, Project.MSG_INFO ); | |||
| } | |||
| /** | |||
| * Log a mesage with the give priority. | |||
| * | |||
| * @param msgLevel the message priority at which this message is to be | |||
| * logged. | |||
| * @param msg Description of Parameter | |||
| */ | |||
| public void log( String msg, int msgLevel ) | |||
| { | |||
| project.log( this, msg, msgLevel ); | |||
| } | |||
| /** | |||
| * Configure this task - if it hasn't been done already. | |||
| * | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| public void maybeConfigure() | |||
| throws TaskException | |||
| { | |||
| if( !invalid ) | |||
| { | |||
| if( wrapper != null ) | |||
| { | |||
| wrapper.maybeConfigure( project ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| getReplacement(); | |||
| } | |||
| } | |||
| protected void setRuntimeConfigurableWrapper( RuntimeConfigurable wrapper ) | |||
| { | |||
| this.wrapper = wrapper; | |||
| } | |||
| protected void handleErrorOutput( String line ) | |||
| { | |||
| log( line, Project.MSG_ERR ); | |||
| } | |||
| protected void handleOutput( String line ) | |||
| { | |||
| log( line, Project.MSG_INFO ); | |||
| } | |||
| /** | |||
| * Set the name with which the task has been invoked. | |||
| * | |||
| * @param type the name the task has been invoked as. | |||
| */ | |||
| void setTaskType( String type ) | |||
| { | |||
| this.taskType = type; | |||
| } | |||
| /** | |||
| * Mark this task as invalid. | |||
| */ | |||
| final void markInvalid() | |||
| { | |||
| invalid = true; | |||
| } | |||
| /** | |||
| * Create an UnknownElement that can be used to replace this task. | |||
| * | |||
| * @return The Replacement value | |||
| */ | |||
| private UnknownElement getReplacement() | |||
| throws TaskException | |||
| { | |||
| if( replacement == null ) | |||
| { | |||
| replacement = new UnknownElement( taskType ); | |||
| replacement.setProject( project ); | |||
| replacement.setTaskType( taskType ); | |||
| replacement.setTaskName( taskName ); | |||
| replacement.setLocation( location ); | |||
| replacement.setOwningTarget( target ); | |||
| replacement.setRuntimeConfigurableWrapper( wrapper ); | |||
| wrapper.setProxy( replacement ); | |||
| target.replaceChild( this, replacement ); | |||
| replacement.maybeConfigure(); | |||
| } | |||
| return replacement; | |||
| } | |||
| } | |||
| @@ -0,0 +1,127 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant; | |||
| import java.lang.reflect.Method; | |||
| import java.lang.reflect.Modifier; | |||
| /** | |||
| * Use introspection to "adapt" an arbitrary Bean ( not extending Task, but with | |||
| * similar patterns). | |||
| * | |||
| * @author costin@dnt.ro | |||
| */ | |||
| public class TaskAdapter extends Task | |||
| { | |||
| Object proxy; | |||
| /** | |||
| * Checks a class, whether it is suitable to be adapted by TaskAdapter. | |||
| * Checks conditions only, which are additionally required for a tasks | |||
| * adapted by TaskAdapter. Thus, this method should be called by {@link | |||
| * Project#checkTaskClass}. Throws a BuildException and logs as | |||
| * Project.MSG_ERR for conditions, that will cause the task execution to | |||
| * fail. Logs other suspicious conditions with Project.MSG_WARN. | |||
| * | |||
| * @param taskClass Description of Parameter | |||
| * @param project Description of Parameter | |||
| */ | |||
| public static void checkTaskClass( final Class taskClass, final Project project ) | |||
| { | |||
| // don't have to check for interface, since then | |||
| // taskClass would be abstract too. | |||
| try | |||
| { | |||
| final Method executeM = taskClass.getMethod( "execute", null ); | |||
| // don't have to check for public, since | |||
| // getMethod finds public method only. | |||
| // don't have to check for abstract, since then | |||
| // taskClass would be abstract too. | |||
| if( !Void.TYPE.equals( executeM.getReturnType() ) ) | |||
| { | |||
| final String message = "return type of execute() should be void but was \"" + executeM.getReturnType() + "\" in " + taskClass; | |||
| project.log( message, Project.MSG_WARN ); | |||
| } | |||
| } | |||
| catch( NoSuchMethodException e ) | |||
| { | |||
| final String message = "No public execute() in " + taskClass; | |||
| project.log( message, Project.MSG_ERR ); | |||
| throw new BuildException( message ); | |||
| } | |||
| } | |||
| /** | |||
| * Set the target object class | |||
| * | |||
| * @param o The new Proxy value | |||
| */ | |||
| public void setProxy( Object o ) | |||
| { | |||
| this.proxy = o; | |||
| } | |||
| public Object getProxy() | |||
| { | |||
| return this.proxy; | |||
| } | |||
| /** | |||
| * Do the execution. | |||
| * | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| Method setProjectM = null; | |||
| try | |||
| { | |||
| Class c = proxy.getClass(); | |||
| setProjectM = | |||
| c.getMethod( "setProject", new Class[]{Project.class} ); | |||
| if( setProjectM != null ) | |||
| { | |||
| setProjectM.invoke( proxy, new Object[]{project} ); | |||
| } | |||
| } | |||
| catch( NoSuchMethodException e ) | |||
| { | |||
| // ignore this if the class being used as a task does not have | |||
| // a set project method. | |||
| } | |||
| catch( Exception ex ) | |||
| { | |||
| log( "Error setting project in " + proxy.getClass(), | |||
| Project.MSG_ERR ); | |||
| throw new BuildException( ex ); | |||
| } | |||
| Method executeM = null; | |||
| try | |||
| { | |||
| Class c = proxy.getClass(); | |||
| executeM = c.getMethod( "execute", new Class[0] ); | |||
| if( executeM == null ) | |||
| { | |||
| log( "No public execute() in " + proxy.getClass(), Project.MSG_ERR ); | |||
| throw new BuildException( "No public execute() in " + proxy.getClass() ); | |||
| } | |||
| executeM.invoke( proxy, null ); | |||
| return; | |||
| } | |||
| catch( Exception ex ) | |||
| { | |||
| log( "Error in " + proxy.getClass(), Project.MSG_ERR ); | |||
| throw new BuildException( ex ); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,28 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant; | |||
| /** | |||
| * Interface for objects which can contain tasks <p> | |||
| * | |||
| * It is recommended that implementations call {@link Task#perform perform} | |||
| * instead of {@link Task#execute execute} for the tasks they contain, as this | |||
| * method ensures that {@link BuildEvent BuildEvents} will be generated.</p> | |||
| * | |||
| * @author <a href="mailto:conor@apache.org">Conor MacNeill</a> | |||
| */ | |||
| public interface TaskContainer | |||
| { | |||
| /** | |||
| * Add a task to this task container | |||
| * | |||
| * @param task the task to be added to this container | |||
| */ | |||
| void addTask( Task task ); | |||
| } | |||
| @@ -0,0 +1,256 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant; | |||
| import java.util.Vector; | |||
| /** | |||
| * Wrapper class that holds all information necessary to create a task or data | |||
| * type that did not exist when Ant started. | |||
| * | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| */ | |||
| public class UnknownElement extends Task | |||
| { | |||
| /** | |||
| * Childelements, holds UnknownElement instances. | |||
| */ | |||
| private Vector children = new Vector(); | |||
| /** | |||
| * Holds the name of the task/type or nested child element of a task/type | |||
| * that hasn't been defined at parser time. | |||
| */ | |||
| private String elementName; | |||
| /** | |||
| * The real object after it has been loaded. | |||
| */ | |||
| private Object realThing; | |||
| public UnknownElement( String elementName ) | |||
| { | |||
| this.elementName = elementName; | |||
| } | |||
| /** | |||
| * return the corresponding XML element name. | |||
| * | |||
| * @return The Tag value | |||
| */ | |||
| public String getTag() | |||
| { | |||
| return elementName; | |||
| } | |||
| /** | |||
| * Return the task instance after it has been created (and if it is a task. | |||
| * | |||
| * @return The Task value | |||
| */ | |||
| public Task getTask() | |||
| { | |||
| if( realThing != null && realThing instanceof Task ) | |||
| { | |||
| return ( Task )realThing; | |||
| } | |||
| return null; | |||
| } | |||
| /** | |||
| * Get the name to use in logging messages. | |||
| * | |||
| * @return the name to use in logging messages. | |||
| */ | |||
| public String getTaskName() | |||
| { | |||
| return realThing == null || !( realThing instanceof Task ) ? | |||
| super.getTaskName() : ( ( Task )realThing ).getTaskName(); | |||
| } | |||
| /** | |||
| * Adds a child element to this element. | |||
| * | |||
| * @param child The feature to be added to the Child attribute | |||
| */ | |||
| public void addChild( UnknownElement child ) | |||
| { | |||
| children.addElement( child ); | |||
| } | |||
| /** | |||
| * Called when the real task has been configured for the first time. | |||
| */ | |||
| public void execute() | |||
| { | |||
| if( realThing == null ) | |||
| { | |||
| // plain impossible to get here, maybeConfigure should | |||
| // have thrown an exception. | |||
| throw new BuildException( "Could not create task of type: " | |||
| + elementName, location ); | |||
| } | |||
| if( realThing instanceof Task ) | |||
| { | |||
| ( ( Task )realThing ).perform(); | |||
| } | |||
| } | |||
| /** | |||
| * creates the real object instance, creates child elements, configures the | |||
| * attributes of the real object. | |||
| * | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| public void maybeConfigure() | |||
| throws BuildException | |||
| { | |||
| realThing = makeObject( this, wrapper ); | |||
| wrapper.setProxy( realThing ); | |||
| if( realThing instanceof Task ) | |||
| { | |||
| ( ( Task )realThing ).setRuntimeConfigurableWrapper( wrapper ); | |||
| } | |||
| handleChildren( realThing, wrapper ); | |||
| wrapper.maybeConfigure( project ); | |||
| if( realThing instanceof Task ) | |||
| { | |||
| target.replaceChild( this, realThing ); | |||
| } | |||
| else | |||
| { | |||
| target.replaceChild( this, wrapper ); | |||
| } | |||
| } | |||
| protected BuildException getNotFoundException( String what, | |||
| String elementName ) | |||
| { | |||
| String lSep = System.getProperty( "line.separator" ); | |||
| String msg = "Could not create " + what + " of type: " + elementName | |||
| + "." + lSep | |||
| + "Ant could not find the task or a class this" + lSep | |||
| + "task relies upon." + lSep | |||
| + "Common solutions are to use taskdef to declare" + lSep | |||
| + "your task, or, if this is an optional task," + lSep | |||
| + "to put the optional.jar and all required libraries of" + lSep | |||
| + "this task in the lib directory of" + lSep | |||
| + "your ant installation (ANT_HOME)." + lSep | |||
| + "There is also the possibility that your build file " + lSep | |||
| + "is written to work with a more recent version of ant " + lSep | |||
| + "than the one you are using, in which case you have to " + lSep | |||
| + "upgrade."; | |||
| return new BuildException( msg, location ); | |||
| } | |||
| /** | |||
| * Creates child elements, creates children of the children, sets attributes | |||
| * of the child elements. | |||
| * | |||
| * @param parent Description of Parameter | |||
| * @param parentWrapper Description of Parameter | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| protected void handleChildren( Object parent, | |||
| RuntimeConfigurable parentWrapper ) | |||
| throws BuildException | |||
| { | |||
| if( parent instanceof TaskAdapter ) | |||
| { | |||
| parent = ( ( TaskAdapter )parent ).getProxy(); | |||
| } | |||
| Class parentClass = parent.getClass(); | |||
| IntrospectionHelper ih = IntrospectionHelper.getHelper( parentClass ); | |||
| for( int i = 0; i < children.size(); i++ ) | |||
| { | |||
| RuntimeConfigurable childWrapper = parentWrapper.getChild( i ); | |||
| UnknownElement child = ( UnknownElement )children.elementAt( i ); | |||
| Object realChild = null; | |||
| if( parent instanceof TaskContainer ) | |||
| { | |||
| realChild = makeTask( child, childWrapper, false ); | |||
| ( ( TaskContainer )parent ).addTask( ( Task )realChild ); | |||
| } | |||
| else | |||
| { | |||
| realChild = ih.createElement( project, parent, child.getTag() ); | |||
| } | |||
| childWrapper.setProxy( realChild ); | |||
| if( parent instanceof TaskContainer ) | |||
| { | |||
| ( ( Task )realChild ).setRuntimeConfigurableWrapper( childWrapper ); | |||
| } | |||
| child.handleChildren( realChild, childWrapper ); | |||
| if( parent instanceof TaskContainer ) | |||
| { | |||
| ( ( Task )realChild ).maybeConfigure(); | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Creates a named task or data type - if it is a task, configure it up to | |||
| * the init() stage. | |||
| * | |||
| * @param ue Description of Parameter | |||
| * @param w Description of Parameter | |||
| * @return Description of the Returned Value | |||
| */ | |||
| protected Object makeObject( UnknownElement ue, RuntimeConfigurable w ) | |||
| { | |||
| Object o = makeTask( ue, w, true ); | |||
| if( o == null ) | |||
| { | |||
| o = project.createDataType( ue.getTag() ); | |||
| } | |||
| if( o == null ) | |||
| { | |||
| throw getNotFoundException( "task or type", ue.getTag() ); | |||
| } | |||
| return o; | |||
| } | |||
| /** | |||
| * Create a named task and configure it up to the init() stage. | |||
| * | |||
| * @param ue Description of Parameter | |||
| * @param w Description of Parameter | |||
| * @param onTopLevel Description of Parameter | |||
| * @return Description of the Returned Value | |||
| */ | |||
| protected Task makeTask( UnknownElement ue, RuntimeConfigurable w, | |||
| boolean onTopLevel ) | |||
| { | |||
| Task task = project.createTask( ue.getTag() ); | |||
| if( task == null && !onTopLevel ) | |||
| { | |||
| throw getNotFoundException( "task", ue.getTag() ); | |||
| } | |||
| if( task != null ) | |||
| { | |||
| task.setLocation( getLocation() ); | |||
| // UnknownElement always has an associated target | |||
| task.setOwningTarget( target ); | |||
| task.init(); | |||
| } | |||
| return task; | |||
| } | |||
| }// UnknownElement | |||
| @@ -0,0 +1,3 @@ | |||
| Manifest-Version: 1.0 | |||
| Created-By: Apache Ant @VERSION@ | |||
| @@ -0,0 +1,550 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.File; | |||
| import java.io.FileOutputStream; | |||
| import java.io.IOException; | |||
| import java.io.PrintStream; | |||
| import java.lang.reflect.Method; | |||
| import java.util.Enumeration; | |||
| import java.util.Hashtable; | |||
| import java.util.Vector; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.BuildListener; | |||
| import org.apache.tools.ant.DefaultLogger; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.ProjectComponent; | |||
| import org.apache.tools.ant.ProjectHelper; | |||
| import org.apache.tools.ant.Task; | |||
| import org.apache.tools.ant.util.FileUtils; | |||
| /** | |||
| * Call Ant in a sub-project <pre> | |||
| * <target name="foo" depends="init"> | |||
| * <ant antfile="build.xml" target="bar" > | |||
| * <property name="property1" value="aaaaa" /> | |||
| * <property name="foo" value="baz" /> | |||
| * </ant></SPAN> </target></SPAN> <target name="bar" | |||
| * depends="init"> <echo message="prop is ${property1} | |||
| * ${foo}" /> </target> </pre> | |||
| * | |||
| * @author costin@dnt.ro | |||
| */ | |||
| public class Ant extends Task | |||
| { | |||
| /** | |||
| * the basedir where is executed the build file | |||
| */ | |||
| private File dir = null; | |||
| /** | |||
| * the build.xml file (can be absolute) in this case dir will be ignored | |||
| */ | |||
| private String antFile = null; | |||
| /** | |||
| * the target to call if any | |||
| */ | |||
| private String target = null; | |||
| /** | |||
| * the output | |||
| */ | |||
| private String output = null; | |||
| /** | |||
| * should we inherit properties from the parent ? | |||
| */ | |||
| private boolean inheritAll = true; | |||
| /** | |||
| * should we inherit references from the parent ? | |||
| */ | |||
| private boolean inheritRefs = false; | |||
| /** | |||
| * the properties to pass to the new project | |||
| */ | |||
| private Vector properties = new Vector(); | |||
| /** | |||
| * the references to pass to the new project | |||
| */ | |||
| private Vector references = new Vector(); | |||
| /** | |||
| * the temporary project created to run the build file | |||
| */ | |||
| private Project newProject; | |||
| /** | |||
| * set the build file, it can be either absolute or relative. If it is | |||
| * absolute, <tt>dir</tt> will be ignored, if it is relative it will be | |||
| * resolved relative to <tt>dir</tt> . | |||
| * | |||
| * @param s The new Antfile value | |||
| */ | |||
| public void setAntfile( String s ) | |||
| { | |||
| // @note: it is a string and not a file to handle relative/absolute | |||
| // otherwise a relative file will be resolved based on the current | |||
| // basedir. | |||
| this.antFile = s; | |||
| } | |||
| /** | |||
| * ... | |||
| * | |||
| * @param d The new Dir value | |||
| */ | |||
| public void setDir( File d ) | |||
| { | |||
| this.dir = d; | |||
| } | |||
| /** | |||
| * If true, inherit all properties from parent Project If false, inherit | |||
| * only userProperties and those defined inside the ant call itself | |||
| * | |||
| * @param value The new InheritAll value | |||
| */ | |||
| public void setInheritAll( boolean value ) | |||
| { | |||
| inheritAll = value; | |||
| } | |||
| /** | |||
| * If true, inherit all references from parent Project If false, inherit | |||
| * only those defined inside the ant call itself | |||
| * | |||
| * @param value The new InheritRefs value | |||
| */ | |||
| public void setInheritRefs( boolean value ) | |||
| { | |||
| inheritRefs = value; | |||
| } | |||
| public void setOutput( String s ) | |||
| { | |||
| this.output = s; | |||
| } | |||
| /** | |||
| * set the target to execute. If none is defined it will execute the default | |||
| * target of the build file | |||
| * | |||
| * @param s The new Target value | |||
| */ | |||
| public void setTarget( String s ) | |||
| { | |||
| this.target = s; | |||
| } | |||
| /** | |||
| * create a reference element that identifies a data type that should be | |||
| * carried over to the new project. | |||
| * | |||
| * @param r The feature to be added to the Reference attribute | |||
| */ | |||
| public void addReference( Reference r ) | |||
| { | |||
| references.addElement( r ); | |||
| } | |||
| /** | |||
| * create a property to pass to the new project as a 'user property' | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public Property createProperty() | |||
| { | |||
| if( newProject == null ) | |||
| { | |||
| reinit(); | |||
| } | |||
| Property p = new Property( true ); | |||
| p.setProject( newProject ); | |||
| p.setTaskName( "property" ); | |||
| properties.addElement( p ); | |||
| return p; | |||
| } | |||
| /** | |||
| * Do the execution. | |||
| * | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| try | |||
| { | |||
| if( newProject == null ) | |||
| { | |||
| reinit(); | |||
| } | |||
| if( ( dir == null ) && ( inheritAll == true ) ) | |||
| { | |||
| dir = project.getBaseDir(); | |||
| } | |||
| initializeProject(); | |||
| if( dir != null ) | |||
| { | |||
| newProject.setBaseDir( dir ); | |||
| newProject.setUserProperty( "basedir", dir.getAbsolutePath() ); | |||
| } | |||
| else | |||
| { | |||
| dir = project.getBaseDir(); | |||
| } | |||
| overrideProperties(); | |||
| if( antFile == null ) | |||
| { | |||
| antFile = "build.xml"; | |||
| } | |||
| File file = FileUtils.newFileUtils().resolveFile( dir, antFile ); | |||
| antFile = file.getAbsolutePath(); | |||
| newProject.setUserProperty( "ant.file", antFile ); | |||
| ProjectHelper.configureProject( newProject, new File( antFile ) ); | |||
| if( target == null ) | |||
| { | |||
| target = newProject.getDefaultTarget(); | |||
| } | |||
| addReferences(); | |||
| // Are we trying to call the target in which we are defined? | |||
| if( newProject.getBaseDir().equals( project.getBaseDir() ) && | |||
| newProject.getProperty( "ant.file" ).equals( project.getProperty( "ant.file" ) ) && | |||
| getOwningTarget() != null && | |||
| target.equals( this.getOwningTarget().getName() ) ) | |||
| { | |||
| throw new BuildException( "ant task calling its own parent target" ); | |||
| } | |||
| newProject.executeTarget( target ); | |||
| } | |||
| finally | |||
| { | |||
| // help the gc | |||
| newProject = null; | |||
| } | |||
| } | |||
| public void init() | |||
| { | |||
| newProject = new Project(); | |||
| newProject.setJavaVersionProperty(); | |||
| newProject.addTaskDefinition( "property", | |||
| ( Class )project.getTaskDefinitions().get( "property" ) ); | |||
| } | |||
| protected void handleErrorOutput( String line ) | |||
| { | |||
| if( newProject != null ) | |||
| { | |||
| newProject.demuxOutput( line, true ); | |||
| } | |||
| else | |||
| { | |||
| super.handleErrorOutput( line ); | |||
| } | |||
| } | |||
| protected void handleOutput( String line ) | |||
| { | |||
| if( newProject != null ) | |||
| { | |||
| newProject.demuxOutput( line, false ); | |||
| } | |||
| else | |||
| { | |||
| super.handleOutput( line ); | |||
| } | |||
| } | |||
| /** | |||
| * Add the references explicitly defined as nested elements to the new | |||
| * project. Also copy over all references that don't override existing | |||
| * references in the new project if inheritall has been requested. | |||
| * | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| private void addReferences() | |||
| throws BuildException | |||
| { | |||
| Hashtable thisReferences = ( Hashtable )project.getReferences().clone(); | |||
| Hashtable newReferences = newProject.getReferences(); | |||
| Enumeration e; | |||
| if( references.size() > 0 ) | |||
| { | |||
| for( e = references.elements(); e.hasMoreElements(); ) | |||
| { | |||
| Reference ref = ( Reference )e.nextElement(); | |||
| String refid = ref.getRefId(); | |||
| if( refid == null ) | |||
| { | |||
| throw new BuildException( "the refid attribute is required for reference elements" ); | |||
| } | |||
| if( !thisReferences.containsKey( refid ) ) | |||
| { | |||
| log( "Parent project doesn't contain any reference '" | |||
| + refid + "'", | |||
| Project.MSG_WARN ); | |||
| continue; | |||
| } | |||
| Object o = thisReferences.remove( refid ); | |||
| String toRefid = ref.getToRefid(); | |||
| if( toRefid == null ) | |||
| { | |||
| toRefid = refid; | |||
| } | |||
| copyReference( refid, toRefid ); | |||
| } | |||
| } | |||
| // Now add all references that are not defined in the | |||
| // subproject, if inheritRefs is true | |||
| if( inheritRefs ) | |||
| { | |||
| for( e = thisReferences.keys(); e.hasMoreElements(); ) | |||
| { | |||
| String key = ( String )e.nextElement(); | |||
| if( newReferences.containsKey( key ) ) | |||
| { | |||
| continue; | |||
| } | |||
| copyReference( key, key ); | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Try to clone and reconfigure the object referenced by oldkey in the | |||
| * parent project and add it to the new project with the key newkey. <p> | |||
| * | |||
| * If we cannot clone it, copy the referenced object itself and keep our | |||
| * fingers crossed.</p> | |||
| * | |||
| * @param oldKey Description of Parameter | |||
| * @param newKey Description of Parameter | |||
| */ | |||
| private void copyReference( String oldKey, String newKey ) | |||
| { | |||
| Object orig = project.getReference( oldKey ); | |||
| Class c = orig.getClass(); | |||
| Object copy = orig; | |||
| try | |||
| { | |||
| Method cloneM = c.getMethod( "clone", new Class[0] ); | |||
| if( cloneM != null ) | |||
| { | |||
| copy = cloneM.invoke( orig, new Object[0] ); | |||
| } | |||
| } | |||
| catch( Exception e ) | |||
| { | |||
| // not Clonable | |||
| } | |||
| if( copy instanceof ProjectComponent ) | |||
| { | |||
| ( ( ProjectComponent )copy ).setProject( newProject ); | |||
| } | |||
| else | |||
| { | |||
| try | |||
| { | |||
| Method setProjectM = | |||
| c.getMethod( "setProject", new Class[]{Project.class} ); | |||
| if( setProjectM != null ) | |||
| { | |||
| setProjectM.invoke( copy, new Object[]{newProject} ); | |||
| } | |||
| } | |||
| catch( NoSuchMethodException e ) | |||
| { | |||
| // ignore this if the class being referenced does not have | |||
| // a set project method. | |||
| } | |||
| catch( Exception e2 ) | |||
| { | |||
| String msg = "Error setting new project instance for reference with id " | |||
| + oldKey; | |||
| throw new BuildException( msg, e2, location ); | |||
| } | |||
| } | |||
| newProject.addReference( newKey, copy ); | |||
| } | |||
| private void initializeProject() | |||
| { | |||
| Vector listeners = project.getBuildListeners(); | |||
| for( int i = 0; i < listeners.size(); i++ ) | |||
| { | |||
| newProject.addBuildListener( ( BuildListener )listeners.elementAt( i ) ); | |||
| } | |||
| if( output != null ) | |||
| { | |||
| try | |||
| { | |||
| PrintStream out = new PrintStream( new FileOutputStream( output ) ); | |||
| DefaultLogger logger = new DefaultLogger(); | |||
| logger.setMessageOutputLevel( Project.MSG_INFO ); | |||
| logger.setOutputPrintStream( out ); | |||
| logger.setErrorPrintStream( out ); | |||
| newProject.addBuildListener( logger ); | |||
| } | |||
| catch( IOException ex ) | |||
| { | |||
| log( "Ant: Can't set output to " + output ); | |||
| } | |||
| } | |||
| Hashtable taskdefs = project.getTaskDefinitions(); | |||
| Enumeration et = taskdefs.keys(); | |||
| while( et.hasMoreElements() ) | |||
| { | |||
| String taskName = ( String )et.nextElement(); | |||
| if( taskName.equals( "property" ) ) | |||
| { | |||
| // we have already added this taskdef in #init | |||
| continue; | |||
| } | |||
| Class taskClass = ( Class )taskdefs.get( taskName ); | |||
| newProject.addTaskDefinition( taskName, taskClass ); | |||
| } | |||
| Hashtable typedefs = project.getDataTypeDefinitions(); | |||
| Enumeration e = typedefs.keys(); | |||
| while( e.hasMoreElements() ) | |||
| { | |||
| String typeName = ( String )e.nextElement(); | |||
| Class typeClass = ( Class )typedefs.get( typeName ); | |||
| newProject.addDataTypeDefinition( typeName, typeClass ); | |||
| } | |||
| // set user-defined or all properties from calling project | |||
| Hashtable prop1; | |||
| if( inheritAll == true ) | |||
| { | |||
| prop1 = project.getProperties(); | |||
| } | |||
| else | |||
| { | |||
| prop1 = project.getUserProperties(); | |||
| // set Java built-in properties separately, | |||
| // b/c we won't inherit them. | |||
| newProject.setSystemProperties(); | |||
| } | |||
| e = prop1.keys(); | |||
| while( e.hasMoreElements() ) | |||
| { | |||
| String arg = ( String )e.nextElement(); | |||
| if( "basedir".equals( arg ) || "ant.file".equals( arg ) ) | |||
| { | |||
| // basedir and ant.file get special treatment in execute() | |||
| continue; | |||
| } | |||
| String value = ( String )prop1.get( arg ); | |||
| if( inheritAll == true ) | |||
| { | |||
| newProject.setProperty( arg, value ); | |||
| } | |||
| else | |||
| { | |||
| newProject.setUserProperty( arg, value ); | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Override the properties in the new project with the one explicitly | |||
| * defined as nested elements here. | |||
| * | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| private void overrideProperties() | |||
| throws BuildException | |||
| { | |||
| Enumeration e = properties.elements(); | |||
| while( e.hasMoreElements() ) | |||
| { | |||
| Property p = ( Property )e.nextElement(); | |||
| p.setProject( newProject ); | |||
| p.execute(); | |||
| } | |||
| } | |||
| private void reinit() | |||
| { | |||
| init(); | |||
| for( int i = 0; i < properties.size(); i++ ) | |||
| { | |||
| Property p = ( Property )properties.elementAt( i ); | |||
| Property newP = ( Property )newProject.createTask( "property" ); | |||
| newP.setName( p.getName() ); | |||
| if( p.getValue() != null ) | |||
| { | |||
| newP.setValue( p.getValue() ); | |||
| } | |||
| if( p.getFile() != null ) | |||
| { | |||
| newP.setFile( p.getFile() ); | |||
| } | |||
| if( p.getResource() != null ) | |||
| { | |||
| newP.setResource( p.getResource() ); | |||
| } | |||
| properties.setElementAt( newP, i ); | |||
| } | |||
| } | |||
| /** | |||
| * Helper class that implements the nested <reference> element of | |||
| * <ant> and <antcall>. | |||
| * | |||
| * @author RT | |||
| */ | |||
| public static class Reference | |||
| extends org.apache.tools.ant.types.Reference | |||
| { | |||
| private String targetid = null; | |||
| public Reference() | |||
| { | |||
| super(); | |||
| } | |||
| public void setToRefid( String targetid ) | |||
| { | |||
| this.targetid = targetid; | |||
| } | |||
| public String getToRefid() | |||
| { | |||
| return targetid; | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,394 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.File; | |||
| import java.io.FileOutputStream; | |||
| import java.io.FileWriter; | |||
| import java.io.IOException; | |||
| import java.io.OutputStreamWriter; | |||
| import java.io.PrintWriter; | |||
| import java.io.UnsupportedEncodingException; | |||
| import java.util.Enumeration; | |||
| import java.util.Hashtable; | |||
| import java.util.Vector; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.IntrospectionHelper; | |||
| import org.apache.tools.ant.Task; | |||
| import org.apache.tools.ant.TaskContainer; | |||
| import org.apache.tools.ant.types.EnumeratedAttribute; | |||
| /** | |||
| * Creates a partial DTD for Ant from the currently known tasks. | |||
| * | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| * @version $Revision$ | |||
| */ | |||
| public class AntStructure extends Task | |||
| { | |||
| private final String lSep = System.getProperty( "line.separator" ); | |||
| private final String BOOLEAN = "%boolean;"; | |||
| private final String TASKS = "%tasks;"; | |||
| private final String TYPES = "%types;"; | |||
| private Hashtable visited = new Hashtable(); | |||
| private File output; | |||
| /** | |||
| * The output file. | |||
| * | |||
| * @param output The new Output value | |||
| */ | |||
| public void setOutput( File output ) | |||
| { | |||
| this.output = output; | |||
| } | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| if( output == null ) | |||
| { | |||
| throw new BuildException( "output attribute is required", location ); | |||
| } | |||
| PrintWriter out = null; | |||
| try | |||
| { | |||
| try | |||
| { | |||
| out = new PrintWriter( new OutputStreamWriter( new FileOutputStream( output ), "UTF8" ) ); | |||
| } | |||
| catch( UnsupportedEncodingException ue ) | |||
| { | |||
| /* | |||
| * Plain impossible with UTF8, see | |||
| * http://java.sun.com/products/jdk/1.2/docs/guide/internat/encoding.doc.html | |||
| * | |||
| * fallback to platform specific anyway. | |||
| */ | |||
| out = new PrintWriter( new FileWriter( output ) ); | |||
| } | |||
| printHead( out, project.getTaskDefinitions().keys(), | |||
| project.getDataTypeDefinitions().keys() ); | |||
| printTargetDecl( out ); | |||
| Enumeration dataTypes = project.getDataTypeDefinitions().keys(); | |||
| while( dataTypes.hasMoreElements() ) | |||
| { | |||
| String typeName = ( String )dataTypes.nextElement(); | |||
| printElementDecl( out, typeName, | |||
| ( Class )project.getDataTypeDefinitions().get( typeName ) ); | |||
| } | |||
| Enumeration tasks = project.getTaskDefinitions().keys(); | |||
| while( tasks.hasMoreElements() ) | |||
| { | |||
| String taskName = ( String )tasks.nextElement(); | |||
| printElementDecl( out, taskName, | |||
| ( Class )project.getTaskDefinitions().get( taskName ) ); | |||
| } | |||
| printTail( out ); | |||
| } | |||
| catch( IOException ioe ) | |||
| { | |||
| throw new BuildException( "Error writing " + output.getAbsolutePath(), | |||
| ioe, location ); | |||
| } | |||
| finally | |||
| { | |||
| if( out != null ) | |||
| { | |||
| out.close(); | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Does this String match the XML-NMTOKEN production? | |||
| * | |||
| * @param s Description of Parameter | |||
| * @return The Nmtoken value | |||
| */ | |||
| protected boolean isNmtoken( String s ) | |||
| { | |||
| for( int i = 0; i < s.length(); i++ ) | |||
| { | |||
| char c = s.charAt( i ); | |||
| // XXX - we are ommitting CombiningChar and Extender here | |||
| if( !Character.isLetterOrDigit( c ) && | |||
| c != '.' && c != '-' && | |||
| c != '_' && c != ':' ) | |||
| { | |||
| return false; | |||
| } | |||
| } | |||
| return true; | |||
| } | |||
| /** | |||
| * Do the Strings all match the XML-NMTOKEN production? <p> | |||
| * | |||
| * Otherwise they are not suitable as an enumerated attribute, for example. | |||
| * </p> | |||
| * | |||
| * @param s Description of Parameter | |||
| * @return Description of the Returned Value | |||
| */ | |||
| protected boolean areNmtokens( String[] s ) | |||
| { | |||
| for( int i = 0; i < s.length; i++ ) | |||
| { | |||
| if( !isNmtoken( s[i] ) ) | |||
| { | |||
| return false; | |||
| } | |||
| } | |||
| return true; | |||
| } | |||
| private void printElementDecl( PrintWriter out, String name, Class element ) | |||
| throws BuildException | |||
| { | |||
| if( visited.containsKey( name ) ) | |||
| { | |||
| return; | |||
| } | |||
| visited.put( name, "" ); | |||
| IntrospectionHelper ih = null; | |||
| try | |||
| { | |||
| ih = IntrospectionHelper.getHelper( element ); | |||
| } | |||
| catch( Throwable t ) | |||
| { | |||
| /* | |||
| * XXX - failed to load the class properly. | |||
| * | |||
| * should we print a warning here? | |||
| */ | |||
| return; | |||
| } | |||
| StringBuffer sb = new StringBuffer( "<!ELEMENT " ); | |||
| sb.append( name ).append( " " ); | |||
| if( org.apache.tools.ant.types.Reference.class.equals( element ) ) | |||
| { | |||
| sb.append( "EMPTY>" ).append( lSep ); | |||
| sb.append( "<!ATTLIST " ).append( name ); | |||
| sb.append( lSep ).append( " id ID #IMPLIED" ); | |||
| sb.append( lSep ).append( " refid IDREF #IMPLIED" ); | |||
| sb.append( ">" ).append( lSep ); | |||
| out.println( sb ); | |||
| return; | |||
| } | |||
| Vector v = new Vector(); | |||
| if( ih.supportsCharacters() ) | |||
| { | |||
| v.addElement( "#PCDATA" ); | |||
| } | |||
| if( TaskContainer.class.isAssignableFrom( element ) ) | |||
| { | |||
| v.addElement( TASKS ); | |||
| } | |||
| Enumeration enum = ih.getNestedElements(); | |||
| while( enum.hasMoreElements() ) | |||
| { | |||
| v.addElement( ( String )enum.nextElement() ); | |||
| } | |||
| if( v.isEmpty() ) | |||
| { | |||
| sb.append( "EMPTY" ); | |||
| } | |||
| else | |||
| { | |||
| sb.append( "(" ); | |||
| for( int i = 0; i < v.size(); i++ ) | |||
| { | |||
| if( i != 0 ) | |||
| { | |||
| sb.append( " | " ); | |||
| } | |||
| sb.append( v.elementAt( i ) ); | |||
| } | |||
| sb.append( ")" ); | |||
| if( v.size() > 1 || !v.elementAt( 0 ).equals( "#PCDATA" ) ) | |||
| { | |||
| sb.append( "*" ); | |||
| } | |||
| } | |||
| sb.append( ">" ); | |||
| out.println( sb ); | |||
| sb.setLength( 0 ); | |||
| sb.append( "<!ATTLIST " ).append( name ); | |||
| sb.append( lSep ).append( " id ID #IMPLIED" ); | |||
| enum = ih.getAttributes(); | |||
| while( enum.hasMoreElements() ) | |||
| { | |||
| String attrName = ( String )enum.nextElement(); | |||
| if( "id".equals( attrName ) ) | |||
| continue; | |||
| sb.append( lSep ).append( " " ).append( attrName ).append( " " ); | |||
| Class type = ih.getAttributeType( attrName ); | |||
| if( type.equals( java.lang.Boolean.class ) || | |||
| type.equals( java.lang.Boolean.TYPE ) ) | |||
| { | |||
| sb.append( BOOLEAN ).append( " " ); | |||
| } | |||
| else if( org.apache.tools.ant.types.Reference.class.isAssignableFrom( type ) ) | |||
| { | |||
| sb.append( "IDREF " ); | |||
| } | |||
| else if( org.apache.tools.ant.types.EnumeratedAttribute.class.isAssignableFrom( type ) ) | |||
| { | |||
| try | |||
| { | |||
| EnumeratedAttribute ea = | |||
| ( EnumeratedAttribute )type.newInstance(); | |||
| String[] values = ea.getValues(); | |||
| if( values == null | |||
| || values.length == 0 | |||
| || !areNmtokens( values ) ) | |||
| { | |||
| sb.append( "CDATA " ); | |||
| } | |||
| else | |||
| { | |||
| sb.append( "(" ); | |||
| for( int i = 0; i < values.length; i++ ) | |||
| { | |||
| if( i != 0 ) | |||
| { | |||
| sb.append( " | " ); | |||
| } | |||
| sb.append( values[i] ); | |||
| } | |||
| sb.append( ") " ); | |||
| } | |||
| } | |||
| catch( InstantiationException ie ) | |||
| { | |||
| sb.append( "CDATA " ); | |||
| } | |||
| catch( IllegalAccessException ie ) | |||
| { | |||
| sb.append( "CDATA " ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| sb.append( "CDATA " ); | |||
| } | |||
| sb.append( "#IMPLIED" ); | |||
| } | |||
| sb.append( ">" ).append( lSep ); | |||
| out.println( sb ); | |||
| for( int i = 0; i < v.size(); i++ ) | |||
| { | |||
| String nestedName = ( String )v.elementAt( i ); | |||
| if( !"#PCDATA".equals( nestedName ) && | |||
| !TASKS.equals( nestedName ) && | |||
| !TYPES.equals( nestedName ) | |||
| ) | |||
| { | |||
| printElementDecl( out, nestedName, ih.getElementType( nestedName ) ); | |||
| } | |||
| } | |||
| } | |||
| private void printHead( PrintWriter out, Enumeration tasks, | |||
| Enumeration types ) | |||
| { | |||
| out.println( "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" ); | |||
| out.println( "<!ENTITY % boolean \"(true|false|on|off|yes|no)\">" ); | |||
| out.print( "<!ENTITY % tasks \"" ); | |||
| boolean first = true; | |||
| while( tasks.hasMoreElements() ) | |||
| { | |||
| String taskName = ( String )tasks.nextElement(); | |||
| if( !first ) | |||
| { | |||
| out.print( " | " ); | |||
| } | |||
| else | |||
| { | |||
| first = false; | |||
| } | |||
| out.print( taskName ); | |||
| } | |||
| out.println( "\">" ); | |||
| out.print( "<!ENTITY % types \"" ); | |||
| first = true; | |||
| while( types.hasMoreElements() ) | |||
| { | |||
| String typeName = ( String )types.nextElement(); | |||
| if( !first ) | |||
| { | |||
| out.print( " | " ); | |||
| } | |||
| else | |||
| { | |||
| first = false; | |||
| } | |||
| out.print( typeName ); | |||
| } | |||
| out.println( "\">" ); | |||
| out.println( "" ); | |||
| out.print( "<!ELEMENT project (target | property | taskdef | " ); | |||
| out.print( TYPES ); | |||
| out.println( ")*>" ); | |||
| out.println( "<!ATTLIST project" ); | |||
| out.println( " name CDATA #REQUIRED" ); | |||
| out.println( " default CDATA #REQUIRED" ); | |||
| out.println( " basedir CDATA #IMPLIED>" ); | |||
| out.println( "" ); | |||
| } | |||
| private void printTail( PrintWriter out ) { } | |||
| private void printTargetDecl( PrintWriter out ) | |||
| { | |||
| out.print( "<!ELEMENT target (" ); | |||
| out.print( TASKS ); | |||
| out.print( " | " ); | |||
| out.print( TYPES ); | |||
| out.println( ")*>" ); | |||
| out.println( "" ); | |||
| out.println( "<!ATTLIST target" ); | |||
| out.println( " id ID #IMPLIED" ); | |||
| out.println( " name CDATA #REQUIRED" ); | |||
| out.println( " if CDATA #IMPLIED" ); | |||
| out.println( " unless CDATA #IMPLIED" ); | |||
| out.println( " depends CDATA #IMPLIED" ); | |||
| out.println( " description CDATA #IMPLIED>" ); | |||
| out.println( "" ); | |||
| } | |||
| } | |||
| @@ -0,0 +1,418 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.File; | |||
| import org.apache.tools.ant.AntClassLoader; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.Task; | |||
| import org.apache.tools.ant.taskdefs.condition.Condition; | |||
| import org.apache.tools.ant.types.EnumeratedAttribute; | |||
| import org.apache.tools.ant.types.Path; | |||
| import org.apache.tools.ant.types.Reference; | |||
| import org.apache.tools.ant.util.FileUtils; | |||
| /** | |||
| * Will set the given property if the requested resource is available at | |||
| * runtime. | |||
| * | |||
| * @author Stefano Mazzocchi <a href="mailto:stefano@apache.org"> | |||
| * stefano@apache.org</a> | |||
| * @author <a href="mailto:umagesh@apache.org">Magesh Umasankar</a> | |||
| */ | |||
| public class Available extends Task implements Condition | |||
| { | |||
| private String value = "true"; | |||
| private String classname; | |||
| private Path classpath; | |||
| private String file; | |||
| private Path filepath; | |||
| private AntClassLoader loader; | |||
| private String property; | |||
| private String resource; | |||
| private FileDir type; | |||
| public void setClassname( String classname ) | |||
| { | |||
| if( !"".equals( classname ) ) | |||
| { | |||
| this.classname = classname; | |||
| } | |||
| } | |||
| public void setClasspath( Path classpath ) | |||
| { | |||
| createClasspath().append( classpath ); | |||
| } | |||
| public void setClasspathRef( Reference r ) | |||
| { | |||
| createClasspath().setRefid( r ); | |||
| } | |||
| public void setFile( String file ) | |||
| { | |||
| this.file = file; | |||
| } | |||
| public void setFilepath( Path filepath ) | |||
| { | |||
| createFilepath().append( filepath ); | |||
| } | |||
| public void setProperty( String property ) | |||
| { | |||
| this.property = property; | |||
| } | |||
| public void setResource( String resource ) | |||
| { | |||
| this.resource = resource; | |||
| } | |||
| /** | |||
| * @param type The new Type value | |||
| * @deprecated setType(String) is deprecated and is replaced with | |||
| * setType(Available.FileDir) to make Ant's Introspection mechanism do | |||
| * the work and also to encapsulate operations on the type in its own | |||
| * class. | |||
| */ | |||
| public void setType( String type ) | |||
| { | |||
| log( "DEPRECATED - The setType(String) method has been deprecated." | |||
| + " Use setType(Available.FileDir) instead." ); | |||
| this.type = new FileDir(); | |||
| this.type.setValue( type ); | |||
| } | |||
| public void setType( FileDir type ) | |||
| { | |||
| this.type = type; | |||
| } | |||
| public void setValue( String value ) | |||
| { | |||
| this.value = value; | |||
| } | |||
| public Path createClasspath() | |||
| { | |||
| if( this.classpath == null ) | |||
| { | |||
| this.classpath = new Path( project ); | |||
| } | |||
| return this.classpath.createPath(); | |||
| } | |||
| public Path createFilepath() | |||
| { | |||
| if( this.filepath == null ) | |||
| { | |||
| this.filepath = new Path( project ); | |||
| } | |||
| return this.filepath.createPath(); | |||
| } | |||
| public boolean eval() | |||
| throws BuildException | |||
| { | |||
| if( classname == null && file == null && resource == null ) | |||
| { | |||
| throw new BuildException( "At least one of (classname|file|resource) is required", location ); | |||
| } | |||
| if( type != null ) | |||
| { | |||
| if( file == null ) | |||
| { | |||
| throw new BuildException( "The type attribute is only valid when specifying the file attribute." ); | |||
| } | |||
| } | |||
| if( classpath != null ) | |||
| { | |||
| classpath.setProject( project ); | |||
| this.loader = new AntClassLoader( project, classpath ); | |||
| } | |||
| if( ( classname != null ) && !checkClass( classname ) ) | |||
| { | |||
| log( "Unable to load class " + classname + " to set property " + property, Project.MSG_VERBOSE ); | |||
| return false; | |||
| } | |||
| if( ( file != null ) && !checkFile() ) | |||
| { | |||
| if( type != null ) | |||
| { | |||
| log( "Unable to find " + type + " " + file + " to set property " + property, Project.MSG_VERBOSE ); | |||
| } | |||
| else | |||
| { | |||
| log( "Unable to find " + file + " to set property " + property, Project.MSG_VERBOSE ); | |||
| } | |||
| return false; | |||
| } | |||
| if( ( resource != null ) && !checkResource( resource ) ) | |||
| { | |||
| log( "Unable to load resource " + resource + " to set property " + property, Project.MSG_VERBOSE ); | |||
| return false; | |||
| } | |||
| if( loader != null ) | |||
| { | |||
| loader.cleanup(); | |||
| } | |||
| return true; | |||
| } | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| if( property == null ) | |||
| { | |||
| throw new BuildException( "property attribute is required", location ); | |||
| } | |||
| if( eval() ) | |||
| { | |||
| String lSep = System.getProperty( "line.separator" ); | |||
| if( null != project.getProperty( property ) ) | |||
| { | |||
| log( "DEPRECATED - <available> used to overide an existing property. " | |||
| + lSep | |||
| + " Build writer should not reuse the same property name for " | |||
| + lSep + "different values." ); | |||
| } | |||
| this.project.setProperty( property, value ); | |||
| } | |||
| } | |||
| private boolean checkClass( String classname ) | |||
| { | |||
| try | |||
| { | |||
| if( loader != null ) | |||
| { | |||
| loader.loadClass( classname ); | |||
| } | |||
| else | |||
| { | |||
| ClassLoader l = this.getClass().getClassLoader(); | |||
| // Can return null to represent the bootstrap class loader. | |||
| // see API docs of Class.getClassLoader. | |||
| if( l != null ) | |||
| { | |||
| l.loadClass( classname ); | |||
| } | |||
| else | |||
| { | |||
| Class.forName( classname ); | |||
| } | |||
| } | |||
| return true; | |||
| } | |||
| catch( ClassNotFoundException e ) | |||
| { | |||
| return false; | |||
| } | |||
| catch( NoClassDefFoundError e ) | |||
| { | |||
| return false; | |||
| } | |||
| } | |||
| private boolean checkFile() | |||
| { | |||
| if( filepath == null ) | |||
| { | |||
| return checkFile( project.resolveFile( file ), file ); | |||
| } | |||
| else | |||
| { | |||
| String[] paths = filepath.list(); | |||
| for( int i = 0; i < paths.length; ++i ) | |||
| { | |||
| log( "Searching " + paths[i], Project.MSG_DEBUG ); | |||
| /* | |||
| * filepath can be a list of directory and/or | |||
| * file names (gen'd via <fileset>) | |||
| * | |||
| * look for: | |||
| * full-pathname specified == path in list | |||
| * full-pathname specified == parent dir of path in list | |||
| * simple name specified == path in list | |||
| * simple name specified == path in list + name | |||
| * simple name specified == parent dir + name | |||
| * simple name specified == parent of parent dir + name | |||
| * | |||
| */ | |||
| File path = new File( paths[i] ); | |||
| // ** full-pathname specified == path in list | |||
| // ** simple name specified == path in list | |||
| if( path.exists() && file.equals( paths[i] ) ) | |||
| { | |||
| if( type == null ) | |||
| { | |||
| log( "Found: " + path, Project.MSG_VERBOSE ); | |||
| return true; | |||
| } | |||
| else if( type.isDir() | |||
| && path.isDirectory() ) | |||
| { | |||
| log( "Found directory: " + path, Project.MSG_VERBOSE ); | |||
| return true; | |||
| } | |||
| else if( type.isFile() | |||
| && path.isFile() ) | |||
| { | |||
| log( "Found file: " + path, Project.MSG_VERBOSE ); | |||
| return true; | |||
| } | |||
| // not the requested type | |||
| return false; | |||
| } | |||
| FileUtils fileUtils = FileUtils.newFileUtils(); | |||
| File parent = fileUtils.getParentFile( path ); | |||
| // ** full-pathname specified == parent dir of path in list | |||
| if( parent != null && parent.exists() | |||
| && file.equals( parent.getAbsolutePath() ) ) | |||
| { | |||
| if( type == null ) | |||
| { | |||
| log( "Found: " + parent, Project.MSG_VERBOSE ); | |||
| return true; | |||
| } | |||
| else if( type.isDir() ) | |||
| { | |||
| log( "Found directory: " + parent, Project.MSG_VERBOSE ); | |||
| return true; | |||
| } | |||
| // not the requested type | |||
| return false; | |||
| } | |||
| // ** simple name specified == path in list + name | |||
| if( path.exists() && path.isDirectory() ) | |||
| { | |||
| if( checkFile( new File( path, file ), | |||
| file + " in " + path ) ) | |||
| { | |||
| return true; | |||
| } | |||
| } | |||
| // ** simple name specified == parent dir + name | |||
| if( parent != null && parent.exists() ) | |||
| { | |||
| if( checkFile( new File( parent, file ), | |||
| file + " in " + parent ) ) | |||
| { | |||
| return true; | |||
| } | |||
| } | |||
| // ** simple name specified == parent of parent dir + name | |||
| if( parent != null ) | |||
| { | |||
| File grandParent = fileUtils.getParentFile( parent ); | |||
| if( grandParent != null && grandParent.exists() ) | |||
| { | |||
| if( checkFile( new File( grandParent, file ), | |||
| file + " in " + grandParent ) ) | |||
| { | |||
| return true; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| return false; | |||
| } | |||
| private boolean checkFile( File f, String text ) | |||
| { | |||
| if( type != null ) | |||
| { | |||
| if( type.isDir() ) | |||
| { | |||
| if( f.isDirectory() ) | |||
| { | |||
| log( "Found directory: " + text, Project.MSG_VERBOSE ); | |||
| } | |||
| return f.isDirectory(); | |||
| } | |||
| else if( type.isFile() ) | |||
| { | |||
| if( f.isFile() ) | |||
| { | |||
| log( "Found file: " + text, Project.MSG_VERBOSE ); | |||
| } | |||
| return f.isFile(); | |||
| } | |||
| } | |||
| if( f.exists() ) | |||
| { | |||
| log( "Found: " + text, Project.MSG_VERBOSE ); | |||
| } | |||
| return f.exists(); | |||
| } | |||
| private boolean checkResource( String resource ) | |||
| { | |||
| if( loader != null ) | |||
| { | |||
| return ( loader.getResourceAsStream( resource ) != null ); | |||
| } | |||
| else | |||
| { | |||
| ClassLoader cL = this.getClass().getClassLoader(); | |||
| if( cL != null ) | |||
| { | |||
| return ( cL.getResourceAsStream( resource ) != null ); | |||
| } | |||
| else | |||
| { | |||
| return | |||
| ( ClassLoader.getSystemResourceAsStream( resource ) != null ); | |||
| } | |||
| } | |||
| } | |||
| public static class FileDir extends EnumeratedAttribute | |||
| { | |||
| private final static String[] values = {"file", "dir"}; | |||
| public String[] getValues() | |||
| { | |||
| return values; | |||
| } | |||
| public boolean isDir() | |||
| { | |||
| return "dir".equalsIgnoreCase( getValue() ); | |||
| } | |||
| public boolean isFile() | |||
| { | |||
| return "file".equalsIgnoreCase( getValue() ); | |||
| } | |||
| public String toString() | |||
| { | |||
| return getValue(); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,114 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.BufferedInputStream; | |||
| import java.io.FileInputStream; | |||
| import java.io.FileOutputStream; | |||
| import java.io.IOException; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.bzip2.CBZip2InputStream; | |||
| /** | |||
| * Expands a file that has been compressed with the BZIP2 algorithm. Normally | |||
| * used to compress non-compressed archives such as TAR files. | |||
| * | |||
| * @author <a href="mailto:umagesh@rediffmail.com">Magesh Umasankar</a> | |||
| */ | |||
| public class BUnzip2 extends Unpack | |||
| { | |||
| private final static String DEFAULT_EXTENSION = ".bz2"; | |||
| protected String getDefaultExtension() | |||
| { | |||
| return DEFAULT_EXTENSION; | |||
| } | |||
| protected void extract() | |||
| { | |||
| if( source.lastModified() > dest.lastModified() ) | |||
| { | |||
| log( "Expanding " + source.getAbsolutePath() + " to " | |||
| + dest.getAbsolutePath() ); | |||
| FileOutputStream out = null; | |||
| CBZip2InputStream zIn = null; | |||
| FileInputStream fis = null; | |||
| BufferedInputStream bis = null; | |||
| try | |||
| { | |||
| out = new FileOutputStream( dest ); | |||
| fis = new FileInputStream( source ); | |||
| bis = new BufferedInputStream( fis ); | |||
| int b = bis.read(); | |||
| if( b != 'B' ) | |||
| { | |||
| throw new BuildException( "Invalid bz2 file.", location ); | |||
| } | |||
| b = bis.read(); | |||
| if( b != 'Z' ) | |||
| { | |||
| throw new BuildException( "Invalid bz2 file.", location ); | |||
| } | |||
| zIn = new CBZip2InputStream( bis ); | |||
| byte[] buffer = new byte[8 * 1024]; | |||
| int count = 0; | |||
| do | |||
| { | |||
| out.write( buffer, 0, count ); | |||
| count = zIn.read( buffer, 0, buffer.length ); | |||
| }while ( count != -1 ); | |||
| } | |||
| catch( IOException ioe ) | |||
| { | |||
| String msg = "Problem expanding bzip2 " + ioe.getMessage(); | |||
| throw new BuildException( msg, ioe, location ); | |||
| } | |||
| finally | |||
| { | |||
| if( bis != null ) | |||
| { | |||
| try | |||
| { | |||
| bis.close(); | |||
| } | |||
| catch( IOException ioex ) | |||
| {} | |||
| } | |||
| if( fis != null ) | |||
| { | |||
| try | |||
| { | |||
| fis.close(); | |||
| } | |||
| catch( IOException ioex ) | |||
| {} | |||
| } | |||
| if( out != null ) | |||
| { | |||
| try | |||
| { | |||
| out.close(); | |||
| } | |||
| catch( IOException ioex ) | |||
| {} | |||
| } | |||
| if( zIn != null ) | |||
| { | |||
| try | |||
| { | |||
| zIn.close(); | |||
| } | |||
| catch( IOException ioex ) | |||
| {} | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,56 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.BufferedOutputStream; | |||
| import java.io.FileOutputStream; | |||
| import java.io.IOException; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.taskdefs.Pack; | |||
| import org.apache.tools.bzip2.CBZip2OutputStream; | |||
| /** | |||
| * Compresses a file with the BZip2 algorithm. Normally used to compress | |||
| * non-compressed archives such as TAR files. | |||
| * | |||
| * @author <a href="mailto:umagesh@rediffmail.com">Magesh Umasankar</a> | |||
| */ | |||
| public class BZip2 extends Pack | |||
| { | |||
| protected void pack() | |||
| { | |||
| CBZip2OutputStream zOut = null; | |||
| try | |||
| { | |||
| BufferedOutputStream bos = | |||
| new BufferedOutputStream( new FileOutputStream( zipFile ) ); | |||
| bos.write( 'B' ); | |||
| bos.write( 'Z' ); | |||
| zOut = new CBZip2OutputStream( bos ); | |||
| zipFile( source, zOut ); | |||
| } | |||
| catch( IOException ioe ) | |||
| { | |||
| String msg = "Problem creating bzip2 " + ioe.getMessage(); | |||
| throw new BuildException( msg, ioe, location ); | |||
| } | |||
| finally | |||
| { | |||
| if( zOut != null ) | |||
| { | |||
| try | |||
| { | |||
| // close up | |||
| zOut.close(); | |||
| } | |||
| catch( IOException e ) | |||
| {} | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,165 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.BufferedReader; | |||
| import java.io.File; | |||
| import java.io.FileReader; | |||
| import java.io.FileWriter; | |||
| import java.io.IOException; | |||
| import java.io.PrintWriter; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Task; | |||
| /** | |||
| * CVSLogin Adds an new entry to a CVS password file | |||
| * | |||
| * @author <a href="jeff@custommonkey.org">Jeff Martin</a> | |||
| * @version $Revision$ | |||
| */ | |||
| public class CVSPass extends Task | |||
| { | |||
| /** | |||
| * CVS Root | |||
| */ | |||
| private String cvsRoot = null; | |||
| /** | |||
| * Password file to add password to | |||
| */ | |||
| private File passFile = null; | |||
| /** | |||
| * Password to add to file | |||
| */ | |||
| private String password = null; | |||
| /** | |||
| * End of line character | |||
| */ | |||
| private final String EOL = System.getProperty( "line.separator" ); | |||
| /** | |||
| * Array contain char conversion data | |||
| */ | |||
| private final char shifts[] = { | |||
| 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, | |||
| 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | |||
| 114, 120, 53, 79, 96, 109, 72, 108, 70, 64, 76, 67, 116, 74, 68, 87, | |||
| 111, 52, 75, 119, 49, 34, 82, 81, 95, 65, 112, 86, 118, 110, 122, 105, | |||
| 41, 57, 83, 43, 46, 102, 40, 89, 38, 103, 45, 50, 42, 123, 91, 35, | |||
| 125, 55, 54, 66, 124, 126, 59, 47, 92, 71, 115, 78, 88, 107, 106, 56, | |||
| 36, 121, 117, 104, 101, 100, 69, 73, 99, 63, 94, 93, 39, 37, 61, 48, | |||
| 58, 113, 32, 90, 44, 98, 60, 51, 33, 97, 62, 77, 84, 80, 85, 223, | |||
| 225, 216, 187, 166, 229, 189, 222, 188, 141, 249, 148, 200, 184, 136, 248, 190, | |||
| 199, 170, 181, 204, 138, 232, 218, 183, 255, 234, 220, 247, 213, 203, 226, 193, | |||
| 174, 172, 228, 252, 217, 201, 131, 230, 197, 211, 145, 238, 161, 179, 160, 212, | |||
| 207, 221, 254, 173, 202, 146, 224, 151, 140, 196, 205, 130, 135, 133, 143, 246, | |||
| 192, 159, 244, 239, 185, 168, 215, 144, 139, 165, 180, 157, 147, 186, 214, 176, | |||
| 227, 231, 219, 169, 175, 156, 206, 198, 129, 164, 150, 210, 154, 177, 134, 127, | |||
| 182, 128, 158, 208, 162, 132, 167, 209, 149, 241, 153, 251, 237, 236, 171, 195, | |||
| 243, 233, 253, 240, 194, 250, 191, 155, 142, 137, 245, 235, 163, 242, 178, 152}; | |||
| public CVSPass() | |||
| { | |||
| passFile = new File( System.getProperty( "user.home" ) + "/.cvspass" ); | |||
| } | |||
| /** | |||
| * Sets cvs root to be added to the password file | |||
| * | |||
| * @param cvsRoot The new Cvsroot value | |||
| */ | |||
| public void setCvsroot( String cvsRoot ) | |||
| { | |||
| this.cvsRoot = cvsRoot; | |||
| } | |||
| /** | |||
| * Sets the password file attribute. | |||
| * | |||
| * @param passFile The new Passfile value | |||
| */ | |||
| public void setPassfile( File passFile ) | |||
| { | |||
| this.passFile = passFile; | |||
| } | |||
| /** | |||
| * Sets the password attribute. | |||
| * | |||
| * @param password The new Password value | |||
| */ | |||
| public void setPassword( String password ) | |||
| { | |||
| this.password = password; | |||
| } | |||
| /** | |||
| * Does the work. | |||
| * | |||
| * @exception BuildException if someting goes wrong with the build | |||
| */ | |||
| public final void execute() | |||
| throws BuildException | |||
| { | |||
| if( cvsRoot == null ) | |||
| throw new BuildException( "cvsroot is required" ); | |||
| if( password == null ) | |||
| throw new BuildException( "password is required" ); | |||
| log( "cvsRoot: " + cvsRoot, project.MSG_DEBUG ); | |||
| log( "password: " + password, project.MSG_DEBUG ); | |||
| log( "passFile: " + passFile, project.MSG_DEBUG ); | |||
| try | |||
| { | |||
| StringBuffer buf = new StringBuffer(); | |||
| if( passFile.exists() ) | |||
| { | |||
| BufferedReader reader = | |||
| new BufferedReader( new FileReader( passFile ) ); | |||
| String line = null; | |||
| while( ( line = reader.readLine() ) != null ) | |||
| { | |||
| if( !line.startsWith( cvsRoot ) ) | |||
| { | |||
| buf.append( line + EOL ); | |||
| } | |||
| } | |||
| reader.close(); | |||
| } | |||
| String pwdfile = buf.toString() + cvsRoot + " A" + mangle( password ); | |||
| log( "Writing -> " + pwdfile, project.MSG_DEBUG ); | |||
| PrintWriter writer = new PrintWriter( new FileWriter( passFile ) ); | |||
| writer.println( pwdfile ); | |||
| writer.close(); | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| throw new BuildException( e ); | |||
| } | |||
| } | |||
| private final String mangle( String password ) | |||
| { | |||
| StringBuffer buf = new StringBuffer(); | |||
| for( int i = 0; i < password.length(); i++ ) | |||
| { | |||
| buf.append( shifts[password.charAt( i )] ); | |||
| } | |||
| return buf.toString(); | |||
| } | |||
| } | |||
| @@ -0,0 +1,125 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Task; | |||
| /** | |||
| * Call another target in the same project. <pre> | |||
| * <target name="foo"> | |||
| * <antcall target="bar"> | |||
| * <param name="property1" value="aaaaa" /> | |||
| * <param name="foo" value="baz" /> | |||
| * </antcall> | |||
| * </target> | |||
| * | |||
| * <target name="bar" depends="init"> | |||
| * <echo message="prop is ${property1} ${foo}" /> | |||
| * </target> | |||
| * </pre> <p> | |||
| * | |||
| * This only works as expected if neither property1 nor foo are defined in the | |||
| * project itself. | |||
| * | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| */ | |||
| public class CallTarget extends Task | |||
| { | |||
| private boolean initialized = false; | |||
| private boolean inheritAll = true; | |||
| private Ant callee; | |||
| private String subTarget; | |||
| /** | |||
| * If true, inherit all properties from parent Project If false, inherit | |||
| * only userProperties and those defined inside the antcall call itself | |||
| * | |||
| * @param inherit The new InheritAll value | |||
| */ | |||
| public void setInheritAll( boolean inherit ) | |||
| { | |||
| inheritAll = inherit; | |||
| } | |||
| public void setTarget( String target ) | |||
| { | |||
| subTarget = target; | |||
| } | |||
| /** | |||
| * create a reference element that identifies a data type that should be | |||
| * carried over to the new project. | |||
| * | |||
| * @param r The feature to be added to the Reference attribute | |||
| */ | |||
| public void addReference( Ant.Reference r ) | |||
| { | |||
| callee.addReference( r ); | |||
| } | |||
| public Property createParam() | |||
| { | |||
| return callee.createProperty(); | |||
| } | |||
| public void execute() | |||
| { | |||
| if( !initialized ) | |||
| { | |||
| init(); | |||
| } | |||
| if( subTarget == null ) | |||
| { | |||
| throw new BuildException( "Attribute target is required.", | |||
| location ); | |||
| } | |||
| callee.setDir( project.getBaseDir() ); | |||
| callee.setAntfile( project.getProperty( "ant.file" ) ); | |||
| callee.setTarget( subTarget ); | |||
| callee.setInheritAll( inheritAll ); | |||
| callee.execute(); | |||
| }//-- setInheritAll | |||
| public void init() | |||
| { | |||
| callee = ( Ant )project.createTask( "ant" ); | |||
| callee.setOwningTarget( target ); | |||
| callee.setTaskName( getTaskName() ); | |||
| callee.setLocation( location ); | |||
| callee.init(); | |||
| initialized = true; | |||
| } | |||
| protected void handleErrorOutput( String line ) | |||
| { | |||
| if( callee != null ) | |||
| { | |||
| callee.handleErrorOutput( line ); | |||
| } | |||
| else | |||
| { | |||
| super.handleErrorOutput( line ); | |||
| } | |||
| } | |||
| protected void handleOutput( String line ) | |||
| { | |||
| if( callee != null ) | |||
| { | |||
| callee.handleOutput( line ); | |||
| } | |||
| else | |||
| { | |||
| super.handleOutput( line ); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,489 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.BufferedReader; | |||
| import java.io.File; | |||
| import java.io.FileInputStream; | |||
| import java.io.FileOutputStream; | |||
| import java.io.IOException; | |||
| import java.io.InputStreamReader; | |||
| import java.security.DigestInputStream; | |||
| import java.security.MessageDigest; | |||
| import java.security.NoSuchAlgorithmException; | |||
| import java.security.NoSuchProviderException; | |||
| import java.util.Enumeration; | |||
| import java.util.Hashtable; | |||
| 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.MatchingTask; | |||
| import org.apache.tools.ant.taskdefs.condition.Condition; | |||
| import org.apache.tools.ant.types.FileSet; | |||
| /** | |||
| * This task can be used to create checksums for files. It can also be used to | |||
| * verify checksums. | |||
| * | |||
| * @author <a href="mailto:umagesh@rediffmail.com">Magesh Umasankar</a> | |||
| */ | |||
| public class Checksum extends MatchingTask implements Condition | |||
| { | |||
| /** | |||
| * File for which checksum is to be calculated. | |||
| */ | |||
| private File file = null; | |||
| /** | |||
| * MessageDigest algorithm to be used. | |||
| */ | |||
| private String algorithm = "MD5"; | |||
| /** | |||
| * MessageDigest Algorithm provider | |||
| */ | |||
| private String provider = null; | |||
| /** | |||
| * Vector to hold source file sets. | |||
| */ | |||
| private Vector filesets = new Vector(); | |||
| /** | |||
| * Stores SourceFile, DestFile pairs and SourceFile, Property String pairs. | |||
| */ | |||
| private Hashtable includeFileMap = new Hashtable(); | |||
| /** | |||
| * File Extension that is be to used to create or identify destination file | |||
| */ | |||
| private String fileext; | |||
| /** | |||
| * Create new destination file? Defaults to false. | |||
| */ | |||
| private boolean forceOverwrite; | |||
| /** | |||
| * is this task being used as a nested condition element? | |||
| */ | |||
| private boolean isCondition; | |||
| /** | |||
| * Message Digest instance | |||
| */ | |||
| private MessageDigest messageDigest; | |||
| /** | |||
| * Holds generated checksum and gets set as a Project Property. | |||
| */ | |||
| private String property; | |||
| /** | |||
| * Contains the result of a checksum verification. ("true" or "false") | |||
| */ | |||
| private String verifyProperty; | |||
| /** | |||
| * Sets the MessageDigest algorithm to be used to calculate the checksum. | |||
| * | |||
| * @param algorithm The new Algorithm value | |||
| */ | |||
| public void setAlgorithm( String algorithm ) | |||
| { | |||
| this.algorithm = algorithm; | |||
| } | |||
| /** | |||
| * Sets the file for which the checksum is to be calculated. | |||
| * | |||
| * @param file The new File value | |||
| */ | |||
| public void setFile( File file ) | |||
| { | |||
| this.file = file; | |||
| } | |||
| /** | |||
| * Sets the File Extension that is be to used to create or identify | |||
| * destination file | |||
| * | |||
| * @param fileext The new Fileext value | |||
| */ | |||
| public void setFileext( String fileext ) | |||
| { | |||
| this.fileext = fileext; | |||
| } | |||
| /** | |||
| * Overwrite existing file irrespective of whether it is newer than the | |||
| * source file? Defaults to false. | |||
| * | |||
| * @param forceOverwrite The new ForceOverwrite value | |||
| */ | |||
| public void setForceOverwrite( boolean forceOverwrite ) | |||
| { | |||
| this.forceOverwrite = forceOverwrite; | |||
| } | |||
| /** | |||
| * Sets the property to hold the generated checksum | |||
| * | |||
| * @param property The new Property value | |||
| */ | |||
| public void setProperty( String property ) | |||
| { | |||
| this.property = property; | |||
| } | |||
| /** | |||
| * Sets the MessageDigest algorithm provider to be used to calculate the | |||
| * checksum. | |||
| * | |||
| * @param provider The new Provider value | |||
| */ | |||
| public void setProvider( String provider ) | |||
| { | |||
| this.provider = provider; | |||
| } | |||
| /** | |||
| * Sets verify property. This project property holds the result of a | |||
| * checksum verification - "true" or "false" | |||
| * | |||
| * @param verifyProperty The new Verifyproperty value | |||
| */ | |||
| public void setVerifyproperty( String verifyProperty ) | |||
| { | |||
| this.verifyProperty = verifyProperty; | |||
| } | |||
| /** | |||
| * Adds a set of files (nested fileset attribute). | |||
| * | |||
| * @param set The feature to be added to the Fileset attribute | |||
| */ | |||
| public void addFileset( FileSet set ) | |||
| { | |||
| filesets.addElement( set ); | |||
| } | |||
| /** | |||
| * Calculate the checksum(s) | |||
| * | |||
| * @return Returns true if the checksum verification test passed, false | |||
| * otherwise. | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| public boolean eval() | |||
| throws BuildException | |||
| { | |||
| isCondition = true; | |||
| return validateAndExecute(); | |||
| } | |||
| /** | |||
| * Calculate the checksum(s). | |||
| * | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| boolean value = validateAndExecute(); | |||
| if( verifyProperty != null ) | |||
| { | |||
| project.setNewProperty( verifyProperty, | |||
| new Boolean( value ).toString() ); | |||
| } | |||
| } | |||
| /** | |||
| * Add key-value pair to the hashtable upon which to later operate upon. | |||
| * | |||
| * @param file The feature to be added to the ToIncludeFileMap attribute | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| private void addToIncludeFileMap( File file ) | |||
| throws BuildException | |||
| { | |||
| if( file != null ) | |||
| { | |||
| if( file.exists() ) | |||
| { | |||
| if( property == null ) | |||
| { | |||
| File dest = new File( file.getParent(), file.getName() + fileext ); | |||
| if( forceOverwrite || isCondition || | |||
| ( file.lastModified() > dest.lastModified() ) ) | |||
| { | |||
| includeFileMap.put( file, dest ); | |||
| } | |||
| else | |||
| { | |||
| log( file + " omitted as " + dest + " is up to date.", | |||
| Project.MSG_VERBOSE ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| includeFileMap.put( file, property ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| String message = "Could not find file " | |||
| + file.getAbsolutePath() | |||
| + " to generate checksum for."; | |||
| log( message ); | |||
| throw new BuildException( message, location ); | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Generate checksum(s) using the message digest created earlier. | |||
| * | |||
| * @return Description of the Returned Value | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| private boolean generateChecksums() | |||
| throws BuildException | |||
| { | |||
| boolean checksumMatches = true; | |||
| FileInputStream fis = null; | |||
| FileOutputStream fos = null; | |||
| try | |||
| { | |||
| for( Enumeration e = includeFileMap.keys(); e.hasMoreElements(); ) | |||
| { | |||
| messageDigest.reset(); | |||
| File src = ( File )e.nextElement(); | |||
| if( !isCondition ) | |||
| { | |||
| log( "Calculating " + algorithm + " checksum for " + src ); | |||
| } | |||
| fis = new FileInputStream( src ); | |||
| DigestInputStream dis = new DigestInputStream( fis, | |||
| messageDigest ); | |||
| while( dis.read() != -1 ) | |||
| ; | |||
| dis.close(); | |||
| fis.close(); | |||
| fis = null; | |||
| byte[] fileDigest = messageDigest.digest(); | |||
| String checksum = ""; | |||
| for( int i = 0; i < fileDigest.length; i++ ) | |||
| { | |||
| String hexStr = Integer.toHexString( 0x00ff & fileDigest[i] ); | |||
| if( hexStr.length() < 2 ) | |||
| { | |||
| checksum += "0"; | |||
| } | |||
| checksum += hexStr; | |||
| } | |||
| //can either be a property name string or a file | |||
| Object destination = includeFileMap.get( src ); | |||
| if( destination instanceof java.lang.String ) | |||
| { | |||
| String prop = ( String )destination; | |||
| if( isCondition ) | |||
| { | |||
| checksumMatches = checksum.equals( property ); | |||
| } | |||
| else | |||
| { | |||
| project.setProperty( prop, checksum ); | |||
| } | |||
| } | |||
| else if( destination instanceof java.io.File ) | |||
| { | |||
| if( isCondition ) | |||
| { | |||
| File existingFile = ( File )destination; | |||
| if( existingFile.exists() && | |||
| existingFile.length() == checksum.length() ) | |||
| { | |||
| fis = new FileInputStream( existingFile ); | |||
| InputStreamReader isr = new InputStreamReader( fis ); | |||
| BufferedReader br = new BufferedReader( isr ); | |||
| String suppliedChecksum = br.readLine(); | |||
| fis.close(); | |||
| fis = null; | |||
| br.close(); | |||
| isr.close(); | |||
| checksumMatches = | |||
| checksum.equals( suppliedChecksum ); | |||
| } | |||
| else | |||
| { | |||
| checksumMatches = false; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| File dest = ( File )destination; | |||
| fos = new FileOutputStream( dest ); | |||
| fos.write( checksum.getBytes() ); | |||
| fos.close(); | |||
| fos = null; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| catch( Exception e ) | |||
| { | |||
| throw new BuildException( e ); | |||
| } | |||
| finally | |||
| { | |||
| if( fis != null ) | |||
| { | |||
| try | |||
| { | |||
| fis.close(); | |||
| } | |||
| catch( IOException e ) | |||
| {} | |||
| } | |||
| if( fos != null ) | |||
| { | |||
| try | |||
| { | |||
| fos.close(); | |||
| } | |||
| catch( IOException e ) | |||
| {} | |||
| } | |||
| } | |||
| return checksumMatches; | |||
| } | |||
| /** | |||
| * Validate attributes and get down to business. | |||
| * | |||
| * @return Description of the Returned Value | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| private boolean validateAndExecute() | |||
| throws BuildException | |||
| { | |||
| if( file == null && filesets.size() == 0 ) | |||
| { | |||
| throw new BuildException( | |||
| "Specify at least one source - a file or a fileset." ); | |||
| } | |||
| if( file != null && file.exists() && file.isDirectory() ) | |||
| { | |||
| throw new BuildException( | |||
| "Checksum cannot be generated for directories" ); | |||
| } | |||
| if( property != null && fileext != null ) | |||
| { | |||
| throw new BuildException( | |||
| "Property and FileExt cannot co-exist." ); | |||
| } | |||
| if( property != null ) | |||
| { | |||
| if( forceOverwrite ) | |||
| { | |||
| throw new BuildException( | |||
| "ForceOverwrite cannot be used when Property is specified" ); | |||
| } | |||
| if( file != null ) | |||
| { | |||
| if( filesets.size() > 0 ) | |||
| { | |||
| throw new BuildException( | |||
| "Multiple files cannot be used when Property is specified" ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| if( filesets.size() > 1 ) | |||
| { | |||
| throw new BuildException( | |||
| "Multiple files cannot be used when Property is specified" ); | |||
| } | |||
| } | |||
| } | |||
| if( verifyProperty != null ) | |||
| { | |||
| isCondition = true; | |||
| } | |||
| if( verifyProperty != null && forceOverwrite ) | |||
| { | |||
| throw new BuildException( | |||
| "VerifyProperty and ForceOverwrite cannot co-exist." ); | |||
| } | |||
| if( isCondition && forceOverwrite ) | |||
| { | |||
| throw new BuildException( | |||
| "ForceOverwrite cannot be used when conditions are being used." ); | |||
| } | |||
| if( fileext == null ) | |||
| { | |||
| fileext = "." + algorithm; | |||
| } | |||
| else if( fileext.trim().length() == 0 ) | |||
| { | |||
| throw new BuildException( | |||
| "File extension when specified must not be an empty string" ); | |||
| } | |||
| messageDigest = null; | |||
| if( provider != null ) | |||
| { | |||
| try | |||
| { | |||
| messageDigest = MessageDigest.getInstance( algorithm, provider ); | |||
| } | |||
| catch( NoSuchAlgorithmException noalgo ) | |||
| { | |||
| throw new BuildException( noalgo ); | |||
| } | |||
| catch( NoSuchProviderException noprovider ) | |||
| { | |||
| throw new BuildException( noprovider ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| try | |||
| { | |||
| messageDigest = MessageDigest.getInstance( algorithm ); | |||
| } | |||
| catch( NoSuchAlgorithmException noalgo ) | |||
| { | |||
| throw new BuildException( noalgo ); | |||
| } | |||
| } | |||
| if( messageDigest == null ) | |||
| { | |||
| throw new BuildException( "Unable to create Message Digest", | |||
| location ); | |||
| } | |||
| addToIncludeFileMap( file ); | |||
| int sizeofFileSet = filesets.size(); | |||
| for( int i = 0; i < sizeofFileSet; i++ ) | |||
| { | |||
| FileSet fs = ( FileSet )filesets.elementAt( i ); | |||
| DirectoryScanner ds = fs.getDirectoryScanner( project ); | |||
| String[] srcFiles = ds.getIncludedFiles(); | |||
| for( int j = 0; j < srcFiles.length; j++ ) | |||
| { | |||
| File src = new File( fs.getDir( project ), srcFiles[j] ); | |||
| addToIncludeFileMap( src ); | |||
| } | |||
| } | |||
| return generateChecksums(); | |||
| } | |||
| } | |||
| @@ -0,0 +1,193 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.myrmidon.framework.Os; | |||
| import org.apache.tools.ant.types.FileSet; | |||
| import org.apache.tools.ant.types.PatternSet; | |||
| /** | |||
| * Chmod equivalent for unix-like environments. | |||
| * | |||
| * @author costin@eng.sun.com | |||
| * @author Mariusz Nowostawski (Marni) <a | |||
| * href="mailto:mnowostawski@infoscience.otago.ac.nz"> | |||
| * mnowostawski@infoscience.otago.ac.nz</a> | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| */ | |||
| public class Chmod extends ExecuteOn | |||
| { | |||
| private FileSet defaultSet = new FileSet(); | |||
| private boolean defaultSetDefined = false; | |||
| private boolean havePerm = false; | |||
| public Chmod() | |||
| { | |||
| super.setExecutable( "chmod" ); | |||
| super.setParallel( true ); | |||
| super.setSkipEmptyFilesets( true ); | |||
| } | |||
| public void setCommand( String e ) | |||
| { | |||
| throw new BuildException( taskType + " doesn\'t support the command attribute", location ); | |||
| } | |||
| /** | |||
| * Sets whether default exclusions should be used or not. | |||
| * | |||
| * @param useDefaultExcludes "true"|"on"|"yes" when default exclusions | |||
| * should be used, "false"|"off"|"no" when they shouldn't be used. | |||
| */ | |||
| public void setDefaultexcludes( boolean useDefaultExcludes ) | |||
| { | |||
| defaultSetDefined = true; | |||
| defaultSet.setDefaultexcludes( useDefaultExcludes ); | |||
| } | |||
| public void setDir( File src ) | |||
| { | |||
| defaultSet.setDir( src ); | |||
| } | |||
| /** | |||
| * Sets the set of exclude patterns. Patterns may be separated by a comma or | |||
| * a space. | |||
| * | |||
| * @param excludes the string containing the exclude patterns | |||
| */ | |||
| public void setExcludes( String excludes ) | |||
| { | |||
| defaultSetDefined = true; | |||
| defaultSet.setExcludes( excludes ); | |||
| } | |||
| public void setExecutable( String e ) | |||
| { | |||
| throw new BuildException( taskType + " doesn\'t support the executable attribute", location ); | |||
| } | |||
| public void setFile( File src ) | |||
| { | |||
| FileSet fs = new FileSet(); | |||
| fs.setDir( new File( src.getParent() ) ); | |||
| fs.createInclude().setName( src.getName() ); | |||
| addFileset( fs ); | |||
| } | |||
| /** | |||
| * Sets the set of include patterns. Patterns may be separated by a comma or | |||
| * a space. | |||
| * | |||
| * @param includes the string containing the include patterns | |||
| */ | |||
| public void setIncludes( String includes ) | |||
| { | |||
| defaultSetDefined = true; | |||
| defaultSet.setIncludes( includes ); | |||
| } | |||
| public void setPerm( String perm ) | |||
| { | |||
| createArg().setValue( perm ); | |||
| havePerm = true; | |||
| } | |||
| public void setSkipEmptyFilesets( boolean skip ) | |||
| { | |||
| throw new BuildException( taskType + " doesn\'t support the skipemptyfileset attribute", location ); | |||
| } | |||
| /** | |||
| * add a name entry on the exclude list | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public PatternSet.NameEntry createExclude() | |||
| { | |||
| defaultSetDefined = true; | |||
| return defaultSet.createExclude(); | |||
| } | |||
| /** | |||
| * add a name entry on the include list | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public PatternSet.NameEntry createInclude() | |||
| { | |||
| defaultSetDefined = true; | |||
| return defaultSet.createInclude(); | |||
| } | |||
| /** | |||
| * add a set of patterns | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public PatternSet createPatternSet() | |||
| { | |||
| defaultSetDefined = true; | |||
| return defaultSet.createPatternSet(); | |||
| } | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| if( defaultSetDefined || defaultSet.getDir( project ) == null ) | |||
| { | |||
| super.execute(); | |||
| } | |||
| else if( isValidOs() ) | |||
| { | |||
| // we are chmodding the given directory | |||
| createArg().setValue( defaultSet.getDir( project ).getPath() ); | |||
| Execute execute = prepareExec(); | |||
| try | |||
| { | |||
| execute.setCommandline( cmdl.getCommandline() ); | |||
| runExecute( execute ); | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| throw new BuildException( "Execute failed: " + e, e, location ); | |||
| } | |||
| finally | |||
| { | |||
| // close the output file if required | |||
| logFlush(); | |||
| } | |||
| } | |||
| } | |||
| protected boolean isValidOs() | |||
| { | |||
| return Os.isFamily( "unix" ) && super.isValidOs(); | |||
| } | |||
| protected void checkConfiguration() | |||
| { | |||
| if( !havePerm ) | |||
| { | |||
| throw new BuildException( "Required attribute perm not set in chmod", | |||
| location ); | |||
| } | |||
| if( defaultSetDefined && defaultSet.getDir( project ) != null ) | |||
| { | |||
| addFileset( defaultSet ); | |||
| } | |||
| super.checkConfiguration(); | |||
| } | |||
| } | |||
| @@ -0,0 +1,73 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.util.Enumeration; | |||
| import java.util.Vector; | |||
| import org.apache.tools.ant.types.PatternSet; | |||
| /** | |||
| * This task will compile and load a new taskdef all in one step. At times, this | |||
| * is useful for eliminating ordering dependencies which otherwise would require | |||
| * multiple executions of Ant. | |||
| * | |||
| * @author Sam Ruby <a href="mailto:rubys@us.ibm.com">rubys@us.ibm.com</a> | |||
| * @deprecated use <taskdef> elements nested into <target>s instead | |||
| */ | |||
| public class CompileTask extends Javac | |||
| { | |||
| protected Vector taskList = new Vector(); | |||
| /** | |||
| * add a new task entry on the task list | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public Taskdef createTaskdef() | |||
| { | |||
| Taskdef task = new Taskdef(); | |||
| taskList.addElement( task ); | |||
| return task; | |||
| } | |||
| /** | |||
| * have execute do nothing | |||
| */ | |||
| public void execute() { } | |||
| /** | |||
| * do all the real work in init | |||
| */ | |||
| public void init() | |||
| { | |||
| log( "!! CompileTask is deprecated. !!" ); | |||
| log( "Use <taskdef> elements nested into <target>s instead" ); | |||
| // create all the include entries from the task defs | |||
| for( Enumeration e = taskList.elements(); e.hasMoreElements(); ) | |||
| { | |||
| Taskdef task = ( Taskdef )e.nextElement(); | |||
| String source = task.getClassname().replace( '.', '/' ) + ".java"; | |||
| PatternSet.NameEntry include = super.createInclude(); | |||
| include.setName( "**/" + source ); | |||
| } | |||
| // execute Javac | |||
| super.init(); | |||
| super.execute(); | |||
| // now define all the new tasks | |||
| for( Enumeration e = taskList.elements(); e.hasMoreElements(); ) | |||
| { | |||
| Taskdef task = ( Taskdef )e.nextElement(); | |||
| task.init(); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,76 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.taskdefs.condition.Condition; | |||
| import org.apache.tools.ant.taskdefs.condition.ConditionBase; | |||
| /** | |||
| * <condition> task as a generalization of <available> and | |||
| * <uptodate> <p> | |||
| * | |||
| * This task supports boolean logic as well as pluggable conditions to decide, | |||
| * whether a property should be set.</p> <p> | |||
| * | |||
| * This task does not extend Task to take advantage of ConditionBase.</p> | |||
| * | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| * @version $Revision$ | |||
| */ | |||
| public class ConditionTask extends ConditionBase | |||
| { | |||
| private String value = "true"; | |||
| private String property; | |||
| /** | |||
| * The name of the property to set. Required. | |||
| * | |||
| * @param p The new Property value | |||
| * @since 1.1 | |||
| */ | |||
| public void setProperty( String p ) | |||
| { | |||
| property = p; | |||
| } | |||
| /** | |||
| * The value for the property to set. Defaults to "true". | |||
| * | |||
| * @param v The new Value value | |||
| * @since 1.1 | |||
| */ | |||
| public void setValue( String v ) | |||
| { | |||
| value = v; | |||
| } | |||
| /** | |||
| * See whether our nested condition holds and set the property. | |||
| * | |||
| * @exception BuildException Description of Exception | |||
| * @since 1.1 | |||
| */ | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| if( countConditions() > 1 ) | |||
| { | |||
| throw new BuildException( "You must not nest more than one condition into <condition>" ); | |||
| } | |||
| if( countConditions() < 1 ) | |||
| { | |||
| throw new BuildException( "You must nest a condition into <condition>" ); | |||
| } | |||
| Condition c = ( Condition )getConditions().nextElement(); | |||
| if( c.eval() ) | |||
| { | |||
| getProject().setNewProperty( property, value ); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,526 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| import java.util.Enumeration; | |||
| import java.util.Hashtable; | |||
| 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.Task; | |||
| import org.apache.tools.ant.types.FileSet; | |||
| import org.apache.tools.ant.types.FilterSet; | |||
| import org.apache.tools.ant.types.FilterSetCollection; | |||
| import org.apache.tools.ant.types.Mapper; | |||
| import org.apache.tools.ant.util.FileNameMapper; | |||
| import org.apache.tools.ant.util.FileUtils; | |||
| import org.apache.tools.ant.util.FlatFileNameMapper; | |||
| import org.apache.tools.ant.util.IdentityMapper; | |||
| import org.apache.tools.ant.util.SourceFileScanner; | |||
| /** | |||
| * A consolidated copy task. Copies a file or directory to a new file or | |||
| * directory. Files are only copied if the source file is newer than the | |||
| * destination file, or when the destination file does not exist. It is possible | |||
| * to explicitly overwrite existing files.</p> <p> | |||
| * | |||
| * This implementation is based on Arnout Kuiper's initial design document, the | |||
| * following mailing list discussions, and the copyfile/copydir tasks.</p> | |||
| * | |||
| * @author Glenn McAllister <a href="mailto:glennm@ca.ibm.com">glennm@ca.ibm.com | |||
| * </a> | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| * @author <A href="gholam@xtra.co.nz">Michael McCallum</A> | |||
| * @author <a href="mailto:umagesh@rediffmail.com">Magesh Umasankar</a> | |||
| */ | |||
| public class Copy extends Task | |||
| { | |||
| protected File file = null;// the source file | |||
| protected File destFile = null;// the destination file | |||
| protected File destDir = null;// the destination directory | |||
| protected Vector filesets = new Vector(); | |||
| protected boolean filtering = false; | |||
| protected boolean preserveLastModified = false; | |||
| protected boolean forceOverwrite = false; | |||
| protected boolean flatten = false; | |||
| protected int verbosity = Project.MSG_VERBOSE; | |||
| protected boolean includeEmpty = true; | |||
| protected Hashtable fileCopyMap = new Hashtable(); | |||
| protected Hashtable dirCopyMap = new Hashtable(); | |||
| protected Hashtable completeDirMap = new Hashtable(); | |||
| protected Mapper mapperElement = null; | |||
| private Vector filterSets = new Vector(); | |||
| private FileUtils fileUtils; | |||
| public Copy() | |||
| { | |||
| fileUtils = FileUtils.newFileUtils(); | |||
| } | |||
| /** | |||
| * Sets a single source file to copy. | |||
| * | |||
| * @param file The new File value | |||
| */ | |||
| public void setFile( File file ) | |||
| { | |||
| this.file = file; | |||
| } | |||
| /** | |||
| * Sets filtering. | |||
| * | |||
| * @param filtering The new Filtering value | |||
| */ | |||
| public void setFiltering( boolean filtering ) | |||
| { | |||
| this.filtering = filtering; | |||
| } | |||
| /** | |||
| * When copying directory trees, the files can be "flattened" into a single | |||
| * directory. If there are multiple files with the same name in the source | |||
| * directory tree, only the first file will be copied into the "flattened" | |||
| * directory, unless the forceoverwrite attribute is true. | |||
| * | |||
| * @param flatten The new Flatten value | |||
| */ | |||
| public void setFlatten( boolean flatten ) | |||
| { | |||
| this.flatten = flatten; | |||
| } | |||
| /** | |||
| * Used to copy empty directories. | |||
| * | |||
| * @param includeEmpty The new IncludeEmptyDirs value | |||
| */ | |||
| public void setIncludeEmptyDirs( boolean includeEmpty ) | |||
| { | |||
| this.includeEmpty = includeEmpty; | |||
| } | |||
| /** | |||
| * Overwrite any existing destination file(s). | |||
| * | |||
| * @param overwrite The new Overwrite value | |||
| */ | |||
| public void setOverwrite( boolean overwrite ) | |||
| { | |||
| this.forceOverwrite = overwrite; | |||
| } | |||
| /** | |||
| * Give the copied files the same last modified time as the original files. | |||
| * | |||
| * @param preserve The new PreserveLastModified value | |||
| * @deprecated setPreserveLastModified(String) has been deprecated and | |||
| * replaced with setPreserveLastModified(boolean) to consistently let | |||
| * the Introspection mechanism work. | |||
| */ | |||
| public void setPreserveLastModified( String preserve ) | |||
| { | |||
| setPreserveLastModified( Project.toBoolean( preserve ) ); | |||
| } | |||
| /** | |||
| * Give the copied files the same last modified time as the original files. | |||
| * | |||
| * @param preserve The new PreserveLastModified value | |||
| */ | |||
| public void setPreserveLastModified( boolean preserve ) | |||
| { | |||
| preserveLastModified = preserve; | |||
| } | |||
| /** | |||
| * Sets the destination directory. | |||
| * | |||
| * @param destDir The new Todir value | |||
| */ | |||
| public void setTodir( File destDir ) | |||
| { | |||
| this.destDir = destDir; | |||
| } | |||
| /** | |||
| * Sets the destination file. | |||
| * | |||
| * @param destFile The new Tofile value | |||
| */ | |||
| public void setTofile( File destFile ) | |||
| { | |||
| this.destFile = destFile; | |||
| } | |||
| /** | |||
| * Used to force listing of all names of copied files. | |||
| * | |||
| * @param verbose The new Verbose value | |||
| */ | |||
| public void setVerbose( boolean verbose ) | |||
| { | |||
| if( verbose ) | |||
| { | |||
| this.verbosity = Project.MSG_INFO; | |||
| } | |||
| else | |||
| { | |||
| this.verbosity = Project.MSG_VERBOSE; | |||
| } | |||
| } | |||
| /** | |||
| * Adds a set of files (nested fileset attribute). | |||
| * | |||
| * @param set The feature to be added to the Fileset attribute | |||
| */ | |||
| public void addFileset( FileSet set ) | |||
| { | |||
| filesets.addElement( set ); | |||
| } | |||
| /** | |||
| * Create a nested filterset | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public FilterSet createFilterSet() | |||
| { | |||
| FilterSet filterSet = new FilterSet(); | |||
| filterSets.addElement( filterSet ); | |||
| return filterSet; | |||
| } | |||
| /** | |||
| * Defines the FileNameMapper to use (nested mapper element). | |||
| * | |||
| * @return Description of the Returned Value | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| public Mapper createMapper() | |||
| throws BuildException | |||
| { | |||
| if( mapperElement != null ) | |||
| { | |||
| throw new BuildException( "Cannot define more than one mapper", | |||
| location ); | |||
| } | |||
| mapperElement = new Mapper( project ); | |||
| return mapperElement; | |||
| } | |||
| /** | |||
| * Performs the copy operation. | |||
| * | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| // make sure we don't have an illegal set of options | |||
| validateAttributes(); | |||
| // deal with the single file | |||
| if( file != null ) | |||
| { | |||
| if( file.exists() ) | |||
| { | |||
| if( destFile == null ) | |||
| { | |||
| destFile = new File( destDir, file.getName() ); | |||
| } | |||
| if( forceOverwrite || | |||
| ( file.lastModified() > destFile.lastModified() ) ) | |||
| { | |||
| fileCopyMap.put( file.getAbsolutePath(), destFile.getAbsolutePath() ); | |||
| } | |||
| else | |||
| { | |||
| log( file + " omitted as " + destFile + " is up to date.", | |||
| Project.MSG_VERBOSE ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| String message = "Could not find file " | |||
| + file.getAbsolutePath() + " to copy."; | |||
| log( message ); | |||
| throw new BuildException( message ); | |||
| } | |||
| } | |||
| // deal with the filesets | |||
| for( int i = 0; i < filesets.size(); i++ ) | |||
| { | |||
| FileSet fs = ( FileSet )filesets.elementAt( i ); | |||
| DirectoryScanner ds = fs.getDirectoryScanner( project ); | |||
| File fromDir = fs.getDir( project ); | |||
| String[] srcFiles = ds.getIncludedFiles(); | |||
| String[] srcDirs = ds.getIncludedDirectories(); | |||
| boolean isEverythingIncluded = ds.isEverythingIncluded(); | |||
| if( isEverythingIncluded | |||
| && !flatten && mapperElement == null ) | |||
| { | |||
| completeDirMap.put( fromDir, destDir ); | |||
| } | |||
| scan( fromDir, destDir, srcFiles, srcDirs ); | |||
| } | |||
| // do all the copy operations now... | |||
| doFileOperations(); | |||
| // clean up destDir again - so this instance can be used a second | |||
| // time without throwing an exception | |||
| if( destFile != null ) | |||
| { | |||
| destDir = null; | |||
| } | |||
| } | |||
| protected FileUtils getFileUtils() | |||
| { | |||
| return fileUtils; | |||
| } | |||
| /** | |||
| * Get the filtersets being applied to this operation. | |||
| * | |||
| * @return a vector of FilterSet objects | |||
| */ | |||
| protected Vector getFilterSets() | |||
| { | |||
| return filterSets; | |||
| } | |||
| protected void buildMap( File fromDir, File toDir, String[] names, | |||
| FileNameMapper mapper, Hashtable map ) | |||
| { | |||
| String[] toCopy = null; | |||
| if( forceOverwrite ) | |||
| { | |||
| Vector v = new Vector(); | |||
| for( int i = 0; i < names.length; i++ ) | |||
| { | |||
| if( mapper.mapFileName( names[i] ) != null ) | |||
| { | |||
| v.addElement( names[i] ); | |||
| } | |||
| } | |||
| toCopy = new String[v.size()]; | |||
| v.copyInto( toCopy ); | |||
| } | |||
| else | |||
| { | |||
| SourceFileScanner ds = new SourceFileScanner( this ); | |||
| toCopy = ds.restrict( names, fromDir, toDir, mapper ); | |||
| } | |||
| for( int i = 0; i < toCopy.length; i++ ) | |||
| { | |||
| File src = new File( fromDir, toCopy[i] ); | |||
| File dest = new File( toDir, mapper.mapFileName( toCopy[i] )[0] ); | |||
| map.put( src.getAbsolutePath(), dest.getAbsolutePath() ); | |||
| } | |||
| } | |||
| /** | |||
| * Actually does the file (and possibly empty directory) copies. This is a | |||
| * good method for subclasses to override. | |||
| */ | |||
| protected void doFileOperations() | |||
| { | |||
| if( fileCopyMap.size() > 0 ) | |||
| { | |||
| log( "Copying " + fileCopyMap.size() + | |||
| " file" + ( fileCopyMap.size() == 1 ? "" : "s" ) + | |||
| " to " + destDir.getAbsolutePath() ); | |||
| Enumeration e = fileCopyMap.keys(); | |||
| while( e.hasMoreElements() ) | |||
| { | |||
| String fromFile = ( String )e.nextElement(); | |||
| String toFile = ( String )fileCopyMap.get( fromFile ); | |||
| if( fromFile.equals( toFile ) ) | |||
| { | |||
| log( "Skipping self-copy of " + fromFile, verbosity ); | |||
| continue; | |||
| } | |||
| try | |||
| { | |||
| log( "Copying " + fromFile + " to " + toFile, verbosity ); | |||
| FilterSetCollection executionFilters = new FilterSetCollection(); | |||
| if( filtering ) | |||
| { | |||
| executionFilters.addFilterSet( project.getGlobalFilterSet() ); | |||
| } | |||
| for( Enumeration filterEnum = filterSets.elements(); filterEnum.hasMoreElements(); ) | |||
| { | |||
| executionFilters.addFilterSet( ( FilterSet )filterEnum.nextElement() ); | |||
| } | |||
| fileUtils.copyFile( fromFile, toFile, executionFilters, | |||
| forceOverwrite, preserveLastModified ); | |||
| } | |||
| catch( IOException ioe ) | |||
| { | |||
| String msg = "Failed to copy " + fromFile + " to " + toFile | |||
| + " due to " + ioe.getMessage(); | |||
| throw new BuildException( msg, ioe, location ); | |||
| } | |||
| } | |||
| } | |||
| if( includeEmpty ) | |||
| { | |||
| Enumeration e = dirCopyMap.elements(); | |||
| int count = 0; | |||
| while( e.hasMoreElements() ) | |||
| { | |||
| File d = new File( ( String )e.nextElement() ); | |||
| if( !d.exists() ) | |||
| { | |||
| if( !d.mkdirs() ) | |||
| { | |||
| log( "Unable to create directory " + d.getAbsolutePath(), Project.MSG_ERR ); | |||
| } | |||
| else | |||
| { | |||
| count++; | |||
| } | |||
| } | |||
| } | |||
| if( count > 0 ) | |||
| { | |||
| log( "Copied " + count + | |||
| " empty director" + | |||
| ( count == 1 ? "y" : "ies" ) + | |||
| " to " + destDir.getAbsolutePath() ); | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Compares source files to destination files to see if they should be | |||
| * copied. | |||
| * | |||
| * @param fromDir Description of Parameter | |||
| * @param toDir Description of Parameter | |||
| * @param files Description of Parameter | |||
| * @param dirs Description of Parameter | |||
| */ | |||
| protected void scan( File fromDir, File toDir, String[] files, String[] dirs ) | |||
| { | |||
| FileNameMapper mapper = null; | |||
| if( mapperElement != null ) | |||
| { | |||
| mapper = mapperElement.getImplementation(); | |||
| } | |||
| else if( flatten ) | |||
| { | |||
| mapper = new FlatFileNameMapper(); | |||
| } | |||
| else | |||
| { | |||
| mapper = new IdentityMapper(); | |||
| } | |||
| buildMap( fromDir, toDir, files, mapper, fileCopyMap ); | |||
| if( includeEmpty ) | |||
| { | |||
| buildMap( fromDir, toDir, dirs, mapper, dirCopyMap ); | |||
| } | |||
| } | |||
| //************************************************************************ | |||
| // protected and private methods | |||
| //************************************************************************ | |||
| /** | |||
| * Ensure we have a consistent and legal set of attributes, and set any | |||
| * internal flags necessary based on different combinations of attributes. | |||
| * | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| protected void validateAttributes() | |||
| throws BuildException | |||
| { | |||
| if( file == null && filesets.size() == 0 ) | |||
| { | |||
| throw new BuildException( "Specify at least one source - a file or a fileset." ); | |||
| } | |||
| if( destFile != null && destDir != null ) | |||
| { | |||
| throw new BuildException( "Only one of tofile and todir may be set." ); | |||
| } | |||
| if( destFile == null && destDir == null ) | |||
| { | |||
| throw new BuildException( "One of tofile or todir must be set." ); | |||
| } | |||
| if( file != null && file.exists() && file.isDirectory() ) | |||
| { | |||
| throw new BuildException( "Use a fileset to copy directories." ); | |||
| } | |||
| if( destFile != null && filesets.size() > 0 ) | |||
| { | |||
| if( filesets.size() > 1 ) | |||
| { | |||
| throw new BuildException( | |||
| "Cannot concatenate multiple files into a single file." ); | |||
| } | |||
| else | |||
| { | |||
| FileSet fs = ( FileSet )filesets.elementAt( 0 ); | |||
| DirectoryScanner ds = fs.getDirectoryScanner( project ); | |||
| String[] srcFiles = ds.getIncludedFiles(); | |||
| if( srcFiles.length > 0 ) | |||
| { | |||
| if( file == null ) | |||
| { | |||
| file = new File( srcFiles[0] ); | |||
| filesets.removeElementAt( 0 ); | |||
| } | |||
| else | |||
| { | |||
| throw new BuildException( | |||
| "Cannot concatenate multiple files into a single file." ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| throw new BuildException( | |||
| "Cannot perform operation from directory to file." ); | |||
| } | |||
| } | |||
| } | |||
| if( destFile != null ) | |||
| { | |||
| destDir = new File( destFile.getParent() );// be 1.1 friendly | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,137 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| import java.util.Enumeration; | |||
| import java.util.Hashtable; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.DirectoryScanner; | |||
| /** | |||
| * Copies a directory. | |||
| * | |||
| * @author James Davidson <a href="mailto:duncan@x180.com">duncan@x180.com</a> | |||
| * @deprecated The copydir task is deprecated. Use copy instead. | |||
| */ | |||
| public class Copydir extends MatchingTask | |||
| { | |||
| private boolean filtering = false; | |||
| private boolean flatten = false; | |||
| private boolean forceOverwrite = false; | |||
| private Hashtable filecopyList = new Hashtable(); | |||
| private File destDir; | |||
| private File srcDir; | |||
| public void setDest( File dest ) | |||
| { | |||
| destDir = dest; | |||
| } | |||
| public void setFiltering( boolean filter ) | |||
| { | |||
| filtering = filter; | |||
| } | |||
| public void setFlatten( boolean flatten ) | |||
| { | |||
| this.flatten = flatten; | |||
| } | |||
| public void setForceoverwrite( boolean force ) | |||
| { | |||
| forceOverwrite = force; | |||
| } | |||
| public void setSrc( File src ) | |||
| { | |||
| srcDir = src; | |||
| } | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| log( "DEPRECATED - The copydir task is deprecated. Use copy instead." ); | |||
| if( srcDir == null ) | |||
| { | |||
| throw new BuildException( "src attribute must be set!", | |||
| location ); | |||
| } | |||
| if( !srcDir.exists() ) | |||
| { | |||
| throw new BuildException( "srcdir " + srcDir.toString() | |||
| + " does not exist!", location ); | |||
| } | |||
| if( destDir == null ) | |||
| { | |||
| throw new BuildException( "The dest attribute must be set.", location ); | |||
| } | |||
| if( srcDir.equals( destDir ) ) | |||
| { | |||
| log( "Warning: src == dest" ); | |||
| } | |||
| DirectoryScanner ds = super.getDirectoryScanner( srcDir ); | |||
| String[] files = ds.getIncludedFiles(); | |||
| scanDir( srcDir, destDir, files ); | |||
| if( filecopyList.size() > 0 ) | |||
| { | |||
| log( "Copying " + filecopyList.size() + " file" | |||
| + ( filecopyList.size() == 1 ? "" : "s" ) | |||
| + " to " + destDir.getAbsolutePath() ); | |||
| Enumeration enum = filecopyList.keys(); | |||
| while( enum.hasMoreElements() ) | |||
| { | |||
| String fromFile = ( String )enum.nextElement(); | |||
| String toFile = ( String )filecopyList.get( fromFile ); | |||
| try | |||
| { | |||
| project.copyFile( fromFile, toFile, filtering, | |||
| forceOverwrite ); | |||
| } | |||
| catch( IOException ioe ) | |||
| { | |||
| String msg = "Failed to copy " + fromFile + " to " + toFile | |||
| + " due to " + ioe.getMessage(); | |||
| throw new BuildException( msg, ioe, location ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| private void scanDir( File from, File to, String[] files ) | |||
| { | |||
| for( int i = 0; i < files.length; i++ ) | |||
| { | |||
| String filename = files[i]; | |||
| File srcFile = new File( from, filename ); | |||
| File destFile; | |||
| if( flatten ) | |||
| { | |||
| destFile = new File( to, new File( filename ).getName() ); | |||
| } | |||
| else | |||
| { | |||
| destFile = new File( to, filename ); | |||
| } | |||
| if( forceOverwrite || | |||
| ( srcFile.lastModified() > destFile.lastModified() ) ) | |||
| { | |||
| filecopyList.put( srcFile.getAbsolutePath(), | |||
| destFile.getAbsolutePath() ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,90 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.Task; | |||
| /** | |||
| * Copies a file. | |||
| * | |||
| * @author duncan@x180.com | |||
| * @deprecated The copyfile task is deprecated. Use copy instead. | |||
| */ | |||
| public class Copyfile extends Task | |||
| { | |||
| private boolean filtering = false; | |||
| private boolean forceOverwrite = false; | |||
| private File destFile; | |||
| private File srcFile; | |||
| public void setDest( File dest ) | |||
| { | |||
| destFile = dest; | |||
| } | |||
| public void setFiltering( String filter ) | |||
| { | |||
| filtering = Project.toBoolean( filter ); | |||
| } | |||
| public void setForceoverwrite( boolean force ) | |||
| { | |||
| forceOverwrite = force; | |||
| } | |||
| public void setSrc( File src ) | |||
| { | |||
| srcFile = src; | |||
| } | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| log( "DEPRECATED - The copyfile task is deprecated. Use copy instead." ); | |||
| if( srcFile == null ) | |||
| { | |||
| throw new BuildException( "The src attribute must be present.", location ); | |||
| } | |||
| if( !srcFile.exists() ) | |||
| { | |||
| throw new BuildException( "src " + srcFile.toString() | |||
| + " does not exist.", location ); | |||
| } | |||
| if( destFile == null ) | |||
| { | |||
| throw new BuildException( "The dest attribute must be present.", location ); | |||
| } | |||
| if( srcFile.equals( destFile ) ) | |||
| { | |||
| log( "Warning: src == dest" ); | |||
| } | |||
| if( forceOverwrite || srcFile.lastModified() > destFile.lastModified() ) | |||
| { | |||
| try | |||
| { | |||
| project.copyFile( srcFile, destFile, filtering, forceOverwrite ); | |||
| } | |||
| catch( IOException ioe ) | |||
| { | |||
| String msg = "Error copying file: " + srcFile.getAbsolutePath() | |||
| + " due to " + ioe.getMessage(); | |||
| throw new BuildException( msg ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,338 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.BufferedOutputStream; | |||
| import java.io.File; | |||
| import java.io.FileOutputStream; | |||
| import java.io.IOException; | |||
| import java.io.OutputStream; | |||
| import java.io.PrintStream; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.Task; | |||
| import org.apache.tools.ant.types.Commandline; | |||
| import org.apache.tools.ant.types.Environment; | |||
| /** | |||
| * @author costin@dnt.ro | |||
| * @author stefano@apache.org | |||
| * @author Wolfgang Werner <a href="mailto:wwerner@picturesafe.de"> | |||
| * wwerner@picturesafe.de</a> | |||
| */ | |||
| public class Cvs extends Task | |||
| { | |||
| private Commandline cmd = new Commandline(); | |||
| /** | |||
| * the CVS command to execute. | |||
| */ | |||
| private String command = "checkout"; | |||
| /** | |||
| * suppress information messages. | |||
| */ | |||
| private boolean quiet = false; | |||
| /** | |||
| * report only, don't change any files. | |||
| */ | |||
| private boolean noexec = false; | |||
| /** | |||
| * CVS port | |||
| */ | |||
| private int port = 0; | |||
| /** | |||
| * CVS password file | |||
| */ | |||
| private File passFile = null; | |||
| /** | |||
| * If true it will stop the build if cvs exits with error. Default is false. | |||
| * (Iulian) | |||
| */ | |||
| private boolean failOnError = false; | |||
| /** | |||
| * the CVSROOT variable. | |||
| */ | |||
| private String cvsRoot; | |||
| /** | |||
| * the CVS_RSH variable. | |||
| */ | |||
| private String cvsRsh; | |||
| /** | |||
| * the directory where the checked out files should be placed. | |||
| */ | |||
| private File dest; | |||
| /** | |||
| * the file to direct standard error from the command. | |||
| */ | |||
| private File error; | |||
| /** | |||
| * the file to direct standard output from the command. | |||
| */ | |||
| private File output; | |||
| /** | |||
| * the package/module to check out. | |||
| */ | |||
| private String pack; | |||
| public void setCommand( String c ) | |||
| { | |||
| this.command = c; | |||
| } | |||
| public void setCvsRoot( String root ) | |||
| { | |||
| // Check if not real cvsroot => set it to null | |||
| if( root != null ) | |||
| { | |||
| if( root.trim().equals( "" ) ) | |||
| root = null; | |||
| } | |||
| this.cvsRoot = root; | |||
| } | |||
| public void setCvsRsh( String rsh ) | |||
| { | |||
| // Check if not real cvsrsh => set it to null | |||
| if( rsh != null ) | |||
| { | |||
| if( rsh.trim().equals( "" ) ) | |||
| rsh = null; | |||
| } | |||
| this.cvsRsh = rsh; | |||
| } | |||
| public void setDate( String p ) | |||
| { | |||
| if( p != null && p.trim().length() > 0 ) | |||
| { | |||
| cmd.createArgument().setValue( "-D" ); | |||
| cmd.createArgument().setValue( p ); | |||
| } | |||
| } | |||
| public void setDest( File dest ) | |||
| { | |||
| this.dest = dest; | |||
| } | |||
| public void setError( File error ) | |||
| { | |||
| this.error = error; | |||
| } | |||
| public void setFailOnError( boolean failOnError ) | |||
| { | |||
| this.failOnError = failOnError; | |||
| } | |||
| public void setNoexec( boolean ne ) | |||
| { | |||
| noexec = ne; | |||
| } | |||
| public void setOutput( File output ) | |||
| { | |||
| this.output = output; | |||
| } | |||
| public void setPackage( String p ) | |||
| { | |||
| this.pack = p; | |||
| } | |||
| public void setPassfile( File passFile ) | |||
| { | |||
| this.passFile = passFile; | |||
| } | |||
| public void setPort( int port ) | |||
| { | |||
| this.port = port; | |||
| } | |||
| public void setQuiet( boolean q ) | |||
| { | |||
| quiet = q; | |||
| } | |||
| public void setTag( String p ) | |||
| { | |||
| // Check if not real tag => set it to null | |||
| if( p != null && p.trim().length() > 0 ) | |||
| { | |||
| cmd.createArgument().setValue( "-r" ); | |||
| cmd.createArgument().setValue( p ); | |||
| } | |||
| } | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| // XXX: we should use JCVS (www.ice.com/JCVS) instead of command line | |||
| // execution so that we don't rely on having native CVS stuff around (SM) | |||
| // We can't do it ourselves as jCVS is GPLed, a third party task | |||
| // outside of jakarta repositories would be possible though (SB). | |||
| Commandline toExecute = new Commandline(); | |||
| toExecute.setExecutable( "cvs" ); | |||
| if( cvsRoot != null ) | |||
| { | |||
| toExecute.createArgument().setValue( "-d" ); | |||
| toExecute.createArgument().setValue( cvsRoot ); | |||
| } | |||
| if( noexec ) | |||
| { | |||
| toExecute.createArgument().setValue( "-n" ); | |||
| } | |||
| if( quiet ) | |||
| { | |||
| toExecute.createArgument().setValue( "-q" ); | |||
| } | |||
| toExecute.createArgument().setLine( command ); | |||
| toExecute.addArguments( cmd.getCommandline() ); | |||
| if( pack != null ) | |||
| { | |||
| toExecute.createArgument().setLine( pack ); | |||
| } | |||
| Environment env = new Environment(); | |||
| if( port > 0 ) | |||
| { | |||
| Environment.Variable var = new Environment.Variable(); | |||
| var.setKey( "CVS_CLIENT_PORT" ); | |||
| var.setValue( String.valueOf( port ) ); | |||
| env.addVariable( var ); | |||
| } | |||
| if( passFile != null ) | |||
| { | |||
| Environment.Variable var = new Environment.Variable(); | |||
| var.setKey( "CVS_PASSFILE" ); | |||
| var.setValue( String.valueOf( passFile ) ); | |||
| env.addVariable( var ); | |||
| } | |||
| if( cvsRsh != null ) | |||
| { | |||
| Environment.Variable var = new Environment.Variable(); | |||
| var.setKey( "CVS_RSH" ); | |||
| var.setValue( String.valueOf( cvsRsh ) ); | |||
| env.addVariable( var ); | |||
| } | |||
| ExecuteStreamHandler streamhandler = null; | |||
| OutputStream outputstream = null; | |||
| OutputStream errorstream = null; | |||
| if( error == null && output == null ) | |||
| { | |||
| streamhandler = new LogStreamHandler( this, Project.MSG_INFO, | |||
| Project.MSG_WARN ); | |||
| } | |||
| else | |||
| { | |||
| if( output != null ) | |||
| { | |||
| try | |||
| { | |||
| outputstream = new PrintStream( new BufferedOutputStream( new FileOutputStream( output ) ) ); | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| throw new BuildException( e ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| outputstream = new LogOutputStream( this, Project.MSG_INFO ); | |||
| } | |||
| if( error != null ) | |||
| { | |||
| try | |||
| { | |||
| errorstream = new PrintStream( new BufferedOutputStream( new FileOutputStream( error ) ) ); | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| throw new BuildException( e ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| errorstream = new LogOutputStream( this, Project.MSG_WARN ); | |||
| } | |||
| streamhandler = new PumpStreamHandler( outputstream, errorstream ); | |||
| } | |||
| Execute exe = new Execute( streamhandler, | |||
| null ); | |||
| exe.setAntRun( project ); | |||
| if( dest == null ) | |||
| dest = project.getBaseDir(); | |||
| exe.setWorkingDirectory( dest ); | |||
| exe.setCommandline( toExecute.getCommandline() ); | |||
| exe.setEnvironment( env.getVariables() ); | |||
| try | |||
| { | |||
| int retCode = exe.execute(); | |||
| /* | |||
| * Throw an exception if cvs exited with error. (Iulian) | |||
| */ | |||
| if( failOnError && retCode != 0 ) | |||
| throw new BuildException( "cvs exited with error code " + retCode ); | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| throw new BuildException( e ); | |||
| } | |||
| finally | |||
| { | |||
| if( output != null ) | |||
| { | |||
| try | |||
| { | |||
| outputstream.close(); | |||
| } | |||
| catch( IOException e ) | |||
| {} | |||
| } | |||
| if( error != null ) | |||
| { | |||
| try | |||
| { | |||
| errorstream.close(); | |||
| } | |||
| catch( IOException e ) | |||
| {} | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,220 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.File; | |||
| import java.io.FileInputStream; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.util.Enumeration; | |||
| import java.util.Properties; | |||
| import org.apache.tools.ant.AntClassLoader; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.Task; | |||
| import org.apache.tools.ant.types.Path; | |||
| import org.apache.tools.ant.types.Reference; | |||
| /** | |||
| * Base class for Taskdef and Typedef - does all the classpath handling and and | |||
| * class loading. | |||
| * | |||
| * @author Costin Manolache | |||
| * @author <a href="stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| */ | |||
| public abstract class Definer extends Task | |||
| { | |||
| private boolean reverseLoader = false; | |||
| private Path classpath; | |||
| private File file; | |||
| private String name; | |||
| private String resource; | |||
| private String value; | |||
| public void setClassname( String v ) | |||
| { | |||
| value = v; | |||
| } | |||
| public void setClasspath( Path classpath ) | |||
| { | |||
| if( this.classpath == null ) | |||
| { | |||
| this.classpath = classpath; | |||
| } | |||
| else | |||
| { | |||
| this.classpath.append( classpath ); | |||
| } | |||
| } | |||
| public void setClasspathRef( Reference r ) | |||
| { | |||
| createClasspath().setRefid( r ); | |||
| } | |||
| public void setFile( File file ) | |||
| { | |||
| this.file = file; | |||
| } | |||
| public void setName( String name ) | |||
| { | |||
| this.name = name; | |||
| } | |||
| public void setResource( String res ) | |||
| { | |||
| this.resource = res; | |||
| } | |||
| public void setReverseLoader( boolean reverseLoader ) | |||
| { | |||
| this.reverseLoader = reverseLoader; | |||
| log( "The reverseloader attribute is DEPRECATED. It will be removed", Project.MSG_WARN ); | |||
| } | |||
| public String getClassname() | |||
| { | |||
| return value; | |||
| } | |||
| public Path createClasspath() | |||
| { | |||
| if( this.classpath == null ) | |||
| { | |||
| this.classpath = new Path( project ); | |||
| } | |||
| return this.classpath.createPath(); | |||
| } | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| AntClassLoader al = createLoader(); | |||
| if( file == null && resource == null ) | |||
| { | |||
| // simple case - one definition | |||
| if( name == null || value == null ) | |||
| { | |||
| String msg = "name or classname attributes of " | |||
| + getTaskName() + " element " | |||
| + "are undefined"; | |||
| throw new BuildException( msg ); | |||
| } | |||
| addDefinition( al, name, value ); | |||
| } | |||
| else | |||
| { | |||
| try | |||
| { | |||
| if( name != null || value != null ) | |||
| { | |||
| String msg = "You must not specify name or value " | |||
| + "together with file or resource."; | |||
| throw new BuildException( msg, location ); | |||
| } | |||
| if( file != null && resource != null ) | |||
| { | |||
| String msg = "You must not specify both, file and resource."; | |||
| throw new BuildException( msg, location ); | |||
| } | |||
| Properties props = new Properties(); | |||
| InputStream is = null; | |||
| if( file != null ) | |||
| { | |||
| log( "Loading definitions from file " + file, | |||
| Project.MSG_VERBOSE ); | |||
| is = new FileInputStream( file ); | |||
| if( is == null ) | |||
| { | |||
| log( "Could not load definitions from file " + file | |||
| + ". It doesn\'t exist.", Project.MSG_WARN ); | |||
| } | |||
| } | |||
| if( resource != null ) | |||
| { | |||
| log( "Loading definitions from resource " + resource, | |||
| Project.MSG_VERBOSE ); | |||
| is = al.getResourceAsStream( resource ); | |||
| if( is == null ) | |||
| { | |||
| log( "Could not load definitions from resource " | |||
| + resource + ". It could not be found.", | |||
| Project.MSG_WARN ); | |||
| } | |||
| } | |||
| if( is != null ) | |||
| { | |||
| props.load( is ); | |||
| Enumeration keys = props.keys(); | |||
| while( keys.hasMoreElements() ) | |||
| { | |||
| String n = ( String )keys.nextElement(); | |||
| String v = props.getProperty( n ); | |||
| addDefinition( al, n, v ); | |||
| } | |||
| } | |||
| } | |||
| catch( IOException ex ) | |||
| { | |||
| throw new BuildException( ex); | |||
| } | |||
| } | |||
| } | |||
| protected abstract void addDefinition( String name, Class c ); | |||
| private void addDefinition( ClassLoader al, String name, String value ) | |||
| throws BuildException | |||
| { | |||
| try | |||
| { | |||
| Class c = al.loadClass( value ); | |||
| AntClassLoader.initializeClass( c ); | |||
| addDefinition( name, c ); | |||
| } | |||
| catch( ClassNotFoundException cnfe ) | |||
| { | |||
| String msg = getTaskName() + " class " + value + | |||
| " cannot be found"; | |||
| throw new BuildException( msg, cnfe, location ); | |||
| } | |||
| catch( NoClassDefFoundError ncdfe ) | |||
| { | |||
| String msg = getTaskName() + " class " + value + | |||
| " cannot be found"; | |||
| throw new BuildException( msg, ncdfe, location ); | |||
| } | |||
| } | |||
| private AntClassLoader createLoader() | |||
| { | |||
| AntClassLoader al = null; | |||
| if( classpath != null ) | |||
| { | |||
| al = new AntClassLoader( project, classpath, !reverseLoader ); | |||
| } | |||
| else | |||
| { | |||
| al = new AntClassLoader( project, Path.systemClasspath, !reverseLoader ); | |||
| } | |||
| // need to load Task via system classloader or the new | |||
| // task we want to define will never be a Task but always | |||
| // be wrapped into a TaskAdapter. | |||
| al.addSystemPackageRoot( "org.apache.tools.ant" ); | |||
| return al; | |||
| } | |||
| } | |||
| @@ -0,0 +1,456 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.File; | |||
| 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.types.FileSet; | |||
| import org.apache.tools.ant.types.PatternSet; | |||
| /** | |||
| * Deletes a file or directory, or set of files defined by a fileset. The | |||
| * original delete task would delete a file, or a set of files using the | |||
| * include/exclude syntax. The deltree task would delete a directory tree. This | |||
| * task combines the functionality of these two originally distinct tasks. <p> | |||
| * | |||
| * Currently Delete extends MatchingTask. This is intend <i>only</i> to provide | |||
| * backwards compatibility for a release. The future position is to use nested | |||
| * filesets exclusively.</p> | |||
| * | |||
| * @author Stefano Mazzocchi <a href="mailto:stefano@apache.org"> | |||
| * stefano@apache.org</a> | |||
| * @author Tom Dimock <a href="mailto:tad1@cornell.edu">tad1@cornell.edu</a> | |||
| * @author Glenn McAllister <a href="mailto:glennm@ca.ibm.com">glennm@ca.ibm.com | |||
| * </a> | |||
| * @author Jon S. Stevens <a href="mailto:jon@latchkey.com">jon@latchkey.com</a> | |||
| */ | |||
| public class Delete extends MatchingTask | |||
| { | |||
| protected File file = null; | |||
| protected File dir = null; | |||
| protected Vector filesets = new Vector(); | |||
| protected boolean usedMatchingTask = false; | |||
| protected boolean includeEmpty = false;// by default, remove matching empty dirs | |||
| private int verbosity = Project.MSG_VERBOSE; | |||
| private boolean quiet = false; | |||
| private boolean failonerror = true; | |||
| /** | |||
| * Sets whether default exclusions should be used or not. | |||
| * | |||
| * @param useDefaultExcludes "true"|"on"|"yes" when default exclusions | |||
| * should be used, "false"|"off"|"no" when they shouldn't be used. | |||
| */ | |||
| public void setDefaultexcludes( boolean useDefaultExcludes ) | |||
| { | |||
| usedMatchingTask = true; | |||
| super.setDefaultexcludes( useDefaultExcludes ); | |||
| } | |||
| /** | |||
| * Set the directory from which files are to be deleted | |||
| * | |||
| * @param dir the directory path. | |||
| */ | |||
| public void setDir( File dir ) | |||
| { | |||
| this.dir = dir; | |||
| } | |||
| /** | |||
| * Sets the set of exclude patterns. Patterns may be separated by a comma or | |||
| * a space. | |||
| * | |||
| * @param excludes the string containing the exclude patterns | |||
| */ | |||
| public void setExcludes( String excludes ) | |||
| { | |||
| usedMatchingTask = true; | |||
| super.setExcludes( excludes ); | |||
| } | |||
| /** | |||
| * Sets the name of the file containing the includes patterns. | |||
| * | |||
| * @param excludesfile A string containing the filename to fetch the include | |||
| * patterns from. | |||
| */ | |||
| public void setExcludesfile( File excludesfile ) | |||
| { | |||
| usedMatchingTask = true; | |||
| super.setExcludesfile( excludesfile ); | |||
| } | |||
| /** | |||
| * this flag means 'note errors to the output, but keep going' | |||
| * | |||
| * @param failonerror true or false | |||
| */ | |||
| public void setFailOnError( boolean failonerror ) | |||
| { | |||
| this.failonerror = failonerror; | |||
| } | |||
| /** | |||
| * Set the name of a single file to be removed. | |||
| * | |||
| * @param file the file to be deleted | |||
| */ | |||
| public void setFile( File file ) | |||
| { | |||
| this.file = file; | |||
| } | |||
| /** | |||
| * Used to delete empty directories. | |||
| * | |||
| * @param includeEmpty The new IncludeEmptyDirs value | |||
| */ | |||
| public void setIncludeEmptyDirs( boolean includeEmpty ) | |||
| { | |||
| this.includeEmpty = includeEmpty; | |||
| } | |||
| /** | |||
| * Sets the set of include patterns. Patterns may be separated by a comma or | |||
| * a space. | |||
| * | |||
| * @param includes the string containing the include patterns | |||
| */ | |||
| public void setIncludes( String includes ) | |||
| { | |||
| usedMatchingTask = true; | |||
| super.setIncludes( includes ); | |||
| } | |||
| /** | |||
| * Sets the name of the file containing the includes patterns. | |||
| * | |||
| * @param includesfile A string containing the filename to fetch the include | |||
| * patterns from. | |||
| */ | |||
| public void setIncludesfile( File includesfile ) | |||
| { | |||
| usedMatchingTask = true; | |||
| super.setIncludesfile( includesfile ); | |||
| } | |||
| /** | |||
| * If the file does not exist, do not display a diagnostic message or modify | |||
| * the exit status to reflect an error. This means that if a file or | |||
| * directory cannot be deleted, then no error is reported. This setting | |||
| * emulates the -f option to the Unix "rm" command. Default is | |||
| * false meaning things are "noisy" | |||
| * | |||
| * @param quiet "true" or "on" | |||
| */ | |||
| public void setQuiet( boolean quiet ) | |||
| { | |||
| this.quiet = quiet; | |||
| if( quiet ) | |||
| { | |||
| this.failonerror = false; | |||
| } | |||
| } | |||
| /** | |||
| * Used to force listing of all names of deleted files. | |||
| * | |||
| * @param verbose "true" or "on" | |||
| */ | |||
| public void setVerbose( boolean verbose ) | |||
| { | |||
| if( verbose ) | |||
| { | |||
| this.verbosity = Project.MSG_INFO; | |||
| } | |||
| else | |||
| { | |||
| this.verbosity = Project.MSG_VERBOSE; | |||
| } | |||
| } | |||
| /** | |||
| * Adds a set of files (nested fileset attribute). | |||
| * | |||
| * @param set The feature to be added to the Fileset attribute | |||
| */ | |||
| public void addFileset( FileSet set ) | |||
| { | |||
| filesets.addElement( set ); | |||
| } | |||
| /** | |||
| * add a name entry on the exclude list | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public PatternSet.NameEntry createExclude() | |||
| { | |||
| usedMatchingTask = true; | |||
| return super.createExclude(); | |||
| } | |||
| /** | |||
| * add a name entry on the include list | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public PatternSet.NameEntry createInclude() | |||
| { | |||
| usedMatchingTask = true; | |||
| return super.createInclude(); | |||
| } | |||
| /** | |||
| * add a set of patterns | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public PatternSet createPatternSet() | |||
| { | |||
| usedMatchingTask = true; | |||
| return super.createPatternSet(); | |||
| } | |||
| /** | |||
| * Delete the file(s). | |||
| * | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| if( usedMatchingTask ) | |||
| { | |||
| log( "DEPRECATED - Use of the implicit FileSet is deprecated. Use a nested fileset element instead." ); | |||
| } | |||
| if( file == null && dir == null && filesets.size() == 0 ) | |||
| { | |||
| throw new BuildException( "At least one of the file or dir attributes, or a fileset element, must be set." ); | |||
| } | |||
| if( quiet && failonerror ) | |||
| { | |||
| throw new BuildException( "quiet and failonerror cannot both be set to true", | |||
| location ); | |||
| } | |||
| // delete the single file | |||
| if( file != null ) | |||
| { | |||
| if( file.exists() ) | |||
| { | |||
| if( file.isDirectory() ) | |||
| { | |||
| log( "Directory " + file.getAbsolutePath() + " cannot be removed using the file attribute. Use dir instead." ); | |||
| } | |||
| else | |||
| { | |||
| log( "Deleting: " + file.getAbsolutePath() ); | |||
| if( !file.delete() ) | |||
| { | |||
| String message = "Unable to delete file " + file.getAbsolutePath(); | |||
| if( failonerror ) | |||
| throw new BuildException( message ); | |||
| else | |||
| log( message, | |||
| quiet ? Project.MSG_VERBOSE : Project.MSG_WARN ); | |||
| } | |||
| } | |||
| } | |||
| else | |||
| { | |||
| log( "Could not find file " + file.getAbsolutePath() + " to delete.", | |||
| Project.MSG_VERBOSE ); | |||
| } | |||
| } | |||
| // delete the directory | |||
| if( dir != null && dir.exists() && dir.isDirectory() && !usedMatchingTask ) | |||
| { | |||
| /* | |||
| * If verbosity is MSG_VERBOSE, that mean we are doing regular logging | |||
| * (backwards as that sounds). In that case, we want to print one | |||
| * message about deleting the top of the directory tree. Otherwise, | |||
| * the removeDir method will handle messages for _all_ directories. | |||
| */ | |||
| if( verbosity == Project.MSG_VERBOSE ) | |||
| { | |||
| log( "Deleting directory " + dir.getAbsolutePath() ); | |||
| } | |||
| removeDir( dir ); | |||
| } | |||
| // delete the files in the filesets | |||
| for( int i = 0; i < filesets.size(); i++ ) | |||
| { | |||
| FileSet fs = ( FileSet )filesets.elementAt( i ); | |||
| try | |||
| { | |||
| DirectoryScanner ds = fs.getDirectoryScanner( project ); | |||
| String[] files = ds.getIncludedFiles(); | |||
| String[] dirs = ds.getIncludedDirectories(); | |||
| removeFiles( fs.getDir( project ), files, dirs ); | |||
| } | |||
| catch( BuildException be ) | |||
| { | |||
| // directory doesn't exist or is not readable | |||
| if( failonerror ) | |||
| { | |||
| throw be; | |||
| } | |||
| else | |||
| { | |||
| log( be.getMessage(), | |||
| quiet ? Project.MSG_VERBOSE : Project.MSG_WARN ); | |||
| } | |||
| } | |||
| } | |||
| // delete the files from the default fileset | |||
| if( usedMatchingTask && dir != null ) | |||
| { | |||
| try | |||
| { | |||
| DirectoryScanner ds = super.getDirectoryScanner( dir ); | |||
| String[] files = ds.getIncludedFiles(); | |||
| String[] dirs = ds.getIncludedDirectories(); | |||
| removeFiles( dir, files, dirs ); | |||
| } | |||
| catch( BuildException be ) | |||
| { | |||
| // directory doesn't exist or is not readable | |||
| if( failonerror ) | |||
| { | |||
| throw be; | |||
| } | |||
| else | |||
| { | |||
| log( be.getMessage(), | |||
| quiet ? Project.MSG_VERBOSE : Project.MSG_WARN ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| //************************************************************************ | |||
| // protected and private methods | |||
| //************************************************************************ | |||
| protected void removeDir( File d ) | |||
| { | |||
| String[] list = d.list(); | |||
| if( list == null ) | |||
| list = new String[0]; | |||
| for( int i = 0; i < list.length; i++ ) | |||
| { | |||
| String s = list[i]; | |||
| File f = new File( d, s ); | |||
| if( f.isDirectory() ) | |||
| { | |||
| removeDir( f ); | |||
| } | |||
| else | |||
| { | |||
| log( "Deleting " + f.getAbsolutePath(), verbosity ); | |||
| if( !f.delete() ) | |||
| { | |||
| String message = "Unable to delete file " + f.getAbsolutePath(); | |||
| if( failonerror ) | |||
| throw new BuildException( message ); | |||
| else | |||
| log( message, | |||
| quiet ? Project.MSG_VERBOSE : Project.MSG_WARN ); | |||
| } | |||
| } | |||
| } | |||
| log( "Deleting directory " + d.getAbsolutePath(), verbosity ); | |||
| if( !d.delete() ) | |||
| { | |||
| String message = "Unable to delete directory " + dir.getAbsolutePath(); | |||
| if( failonerror ) | |||
| throw new BuildException( message ); | |||
| else | |||
| log( message, | |||
| quiet ? Project.MSG_VERBOSE : Project.MSG_WARN ); | |||
| } | |||
| } | |||
| /** | |||
| * remove an array of files in a directory, and a list of subdirectories | |||
| * which will only be deleted if 'includeEmpty' is true | |||
| * | |||
| * @param d directory to work from | |||
| * @param files array of files to delete; can be of zero length | |||
| * @param dirs array of directories to delete; can of zero length | |||
| */ | |||
| protected void removeFiles( File d, String[] files, String[] dirs ) | |||
| { | |||
| if( files.length > 0 ) | |||
| { | |||
| log( "Deleting " + files.length + " files from " + d.getAbsolutePath() ); | |||
| for( int j = 0; j < files.length; j++ ) | |||
| { | |||
| File f = new File( d, files[j] ); | |||
| log( "Deleting " + f.getAbsolutePath(), verbosity ); | |||
| if( !f.delete() ) | |||
| { | |||
| String message = "Unable to delete file " + f.getAbsolutePath(); | |||
| if( failonerror ) | |||
| throw new BuildException( message ); | |||
| else | |||
| log( message, | |||
| quiet ? Project.MSG_VERBOSE : Project.MSG_WARN ); | |||
| } | |||
| } | |||
| } | |||
| if( dirs.length > 0 && includeEmpty ) | |||
| { | |||
| int dirCount = 0; | |||
| for( int j = dirs.length - 1; j >= 0; j-- ) | |||
| { | |||
| File dir = new File( d, dirs[j] ); | |||
| String[] dirFiles = dir.list(); | |||
| if( dirFiles == null || dirFiles.length == 0 ) | |||
| { | |||
| log( "Deleting " + dir.getAbsolutePath(), verbosity ); | |||
| if( !dir.delete() ) | |||
| { | |||
| String message = "Unable to delete directory " | |||
| + dir.getAbsolutePath(); | |||
| if( failonerror ) | |||
| throw new BuildException( message ); | |||
| else | |||
| log( message, | |||
| quiet ? Project.MSG_VERBOSE : Project.MSG_WARN ); | |||
| } | |||
| else | |||
| { | |||
| dirCount++; | |||
| } | |||
| } | |||
| } | |||
| if( dirCount > 0 ) | |||
| { | |||
| log( "Deleted " + dirCount + " director" + | |||
| ( dirCount == 1 ? "y" : "ies" ) + | |||
| " from " + d.getAbsolutePath() ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,103 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Task; | |||
| /** | |||
| * @author duncan@x180.com | |||
| * @deprecated The deltree task is deprecated. Use delete instead. | |||
| */ | |||
| public class Deltree extends Task | |||
| { | |||
| private File dir; | |||
| public void setDir( File dir ) | |||
| { | |||
| this.dir = dir; | |||
| } | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| log( "DEPRECATED - The deltree task is deprecated. Use delete instead." ); | |||
| if( dir == null ) | |||
| { | |||
| throw new BuildException( "dir attribute must be set!", location ); | |||
| } | |||
| if( dir.exists() ) | |||
| { | |||
| if( !dir.isDirectory() ) | |||
| { | |||
| if( !dir.delete() ) | |||
| { | |||
| throw new BuildException( "Unable to delete directory " | |||
| + dir.getAbsolutePath(), | |||
| location ); | |||
| } | |||
| return; | |||
| // String msg = "Given dir: " + dir.getAbsolutePath() + | |||
| // " is not a dir"; | |||
| // throw new BuildException(msg); | |||
| } | |||
| log( "Deleting: " + dir.getAbsolutePath() ); | |||
| try | |||
| { | |||
| removeDir( dir ); | |||
| } | |||
| catch( IOException ioe ) | |||
| { | |||
| String msg = "Unable to delete " + dir.getAbsolutePath(); | |||
| throw new BuildException( msg, location ); | |||
| } | |||
| } | |||
| } | |||
| private void removeDir( File dir ) | |||
| throws IOException | |||
| { | |||
| // check to make sure that the given dir isn't a symlink | |||
| // the comparison of absolute path and canonical path | |||
| // catches this | |||
| // if (dir.getCanonicalPath().equals(dir.getAbsolutePath())) { | |||
| // (costin) It will not work if /home/costin is symlink to /da0/home/costin ( taz | |||
| // for example ) | |||
| String[] list = dir.list(); | |||
| for( int i = 0; i < list.length; i++ ) | |||
| { | |||
| String s = list[i]; | |||
| File f = new File( dir, s ); | |||
| if( f.isDirectory() ) | |||
| { | |||
| removeDir( f ); | |||
| } | |||
| else | |||
| { | |||
| if( !f.delete() ) | |||
| { | |||
| throw new BuildException( "Unable to delete file " + f.getAbsolutePath() ); | |||
| } | |||
| } | |||
| } | |||
| if( !dir.delete() ) | |||
| { | |||
| throw new BuildException( "Unable to delete directory " + dir.getAbsolutePath() ); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,308 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.File; | |||
| import java.util.Date; | |||
| import java.util.Enumeration; | |||
| 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.myrmidon.framework.Os; | |||
| import org.apache.tools.ant.types.FileList; | |||
| import org.apache.tools.ant.types.FileSet; | |||
| /** | |||
| * A Task to record explicit dependencies. If any of the target files are out of | |||
| * date with respect to any of the source files, all target files are removed. | |||
| * This is useful where dependencies cannot be computed (for example, | |||
| * dynamically interpreted parameters or files that need to stay in synch but | |||
| * are not directly linked) or where the ant task in question could compute them | |||
| * but does not (for example, the linked DTD for an XML file using the style | |||
| * task). nested arguments: | |||
| * <ul> | |||
| * <li> srcfileset (fileset describing the source files to examine) | |||
| * <li> srcfilelist (filelist describing the source files to examine) | |||
| * <li> targetfileset (fileset describing the target files to examine) | |||
| * <li> targetfilelist (filelist describing the target files to examine) | |||
| * </ul> | |||
| * At least one instance of either a fileset or filelist for both source and | |||
| * target are required. <p> | |||
| * | |||
| * This task will examine each of the source files against each of the target | |||
| * files. If any target files are out of date with respect to any of the source | |||
| * files, all targets are removed. If any files named in a (src or target) | |||
| * filelist do not exist, all targets are removed. Hint: If missing files should | |||
| * be ignored, specify them as include patterns in filesets, rather than using | |||
| * filelists. </p> <p> | |||
| * | |||
| * This task attempts to optimize speed of dependency checking. It will stop | |||
| * after the first out of date file is found and remove all targets, rather than | |||
| * exhaustively checking every source vs target combination unnecessarily. </p> | |||
| * <p> | |||
| * | |||
| * Example uses: | |||
| * <ul> | |||
| * <li> Record the fact that an XML file must be up to date with respect to | |||
| * its XSD (Schema file), even though the XML file itself includes no | |||
| * reference to its XSD. </li> | |||
| * <li> Record the fact that an XSL stylesheet includes other sub-stylesheets | |||
| * </li> | |||
| * <li> Record the fact that java files must be recompiled if the ant build | |||
| * file changes </li> | |||
| * </ul> | |||
| * | |||
| * | |||
| * @author <a href="mailto:cstrong@arielpartners.com">Craeg Strong</a> | |||
| * @version $Revision$ $Date$ | |||
| */ | |||
| public class DependSet extends MatchingTask | |||
| { | |||
| private Vector sourceFileSets = new Vector(); | |||
| private Vector sourceFileLists = new Vector(); | |||
| private Vector targetFileSets = new Vector(); | |||
| private Vector targetFileLists = new Vector(); | |||
| /** | |||
| * Creates a new DependSet Task. | |||
| */ | |||
| public DependSet() { } | |||
| /** | |||
| * Nested <srcfilelist> element. | |||
| * | |||
| * @param fl The feature to be added to the Srcfilelist attribute | |||
| */ | |||
| public void addSrcfilelist( FileList fl ) | |||
| { | |||
| sourceFileLists.addElement( fl ); | |||
| }//-- DependSet | |||
| /** | |||
| * Nested <srcfileset> element. | |||
| * | |||
| * @param fs The feature to be added to the Srcfileset attribute | |||
| */ | |||
| public void addSrcfileset( FileSet fs ) | |||
| { | |||
| sourceFileSets.addElement( fs ); | |||
| } | |||
| /** | |||
| * Nested <targetfilelist> element. | |||
| * | |||
| * @param fl The feature to be added to the Targetfilelist attribute | |||
| */ | |||
| public void addTargetfilelist( FileList fl ) | |||
| { | |||
| targetFileLists.addElement( fl ); | |||
| } | |||
| /** | |||
| * Nested <targetfileset> element. | |||
| * | |||
| * @param fs The feature to be added to the Targetfileset attribute | |||
| */ | |||
| public void addTargetfileset( FileSet fs ) | |||
| { | |||
| targetFileSets.addElement( fs ); | |||
| } | |||
| /** | |||
| * Executes the task. | |||
| * | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| if( ( sourceFileSets.size() == 0 ) && ( sourceFileLists.size() == 0 ) ) | |||
| { | |||
| throw new BuildException( "At least one <srcfileset> or <srcfilelist> element must be set" ); | |||
| } | |||
| if( ( targetFileSets.size() == 0 ) && ( targetFileLists.size() == 0 ) ) | |||
| { | |||
| throw new BuildException( "At least one <targetfileset> or <targetfilelist> element must be set" ); | |||
| } | |||
| long now = ( new Date() ).getTime(); | |||
| /* | |||
| * If we're on Windows, we have to munge the time up to 2 secs to | |||
| * be able to check file modification times. | |||
| * (Windows has a max resolution of two secs for modification times) | |||
| */ | |||
| if( Os.isFamily( "windows" ) ) | |||
| { | |||
| now += 2000; | |||
| } | |||
| // | |||
| // Grab all the target files specified via filesets | |||
| // | |||
| Vector allTargets = new Vector(); | |||
| Enumeration enumTargetSets = targetFileSets.elements(); | |||
| while( enumTargetSets.hasMoreElements() ) | |||
| { | |||
| FileSet targetFS = ( FileSet )enumTargetSets.nextElement(); | |||
| DirectoryScanner targetDS = targetFS.getDirectoryScanner( project ); | |||
| String[] targetFiles = targetDS.getIncludedFiles(); | |||
| for( int i = 0; i < targetFiles.length; i++ ) | |||
| { | |||
| File dest = new File( targetFS.getDir( project ), targetFiles[i] ); | |||
| allTargets.addElement( dest ); | |||
| if( dest.lastModified() > now ) | |||
| { | |||
| log( "Warning: " + targetFiles[i] + " modified in the future.", | |||
| Project.MSG_WARN ); | |||
| } | |||
| } | |||
| } | |||
| // | |||
| // Grab all the target files specified via filelists | |||
| // | |||
| boolean upToDate = true; | |||
| Enumeration enumTargetLists = targetFileLists.elements(); | |||
| while( enumTargetLists.hasMoreElements() ) | |||
| { | |||
| FileList targetFL = ( FileList )enumTargetLists.nextElement(); | |||
| String[] targetFiles = targetFL.getFiles( project ); | |||
| for( int i = 0; i < targetFiles.length; i++ ) | |||
| { | |||
| File dest = new File( targetFL.getDir( project ), targetFiles[i] ); | |||
| if( !dest.exists() ) | |||
| { | |||
| log( targetFiles[i] + " does not exist.", Project.MSG_VERBOSE ); | |||
| upToDate = false; | |||
| continue; | |||
| } | |||
| else | |||
| { | |||
| allTargets.addElement( dest ); | |||
| } | |||
| if( dest.lastModified() > now ) | |||
| { | |||
| log( "Warning: " + targetFiles[i] + " modified in the future.", | |||
| Project.MSG_WARN ); | |||
| } | |||
| } | |||
| } | |||
| // | |||
| // Check targets vs source files specified via filesets | |||
| // | |||
| if( upToDate ) | |||
| { | |||
| Enumeration enumSourceSets = sourceFileSets.elements(); | |||
| while( upToDate && enumSourceSets.hasMoreElements() ) | |||
| { | |||
| FileSet sourceFS = ( FileSet )enumSourceSets.nextElement(); | |||
| DirectoryScanner sourceDS = sourceFS.getDirectoryScanner( project ); | |||
| String[] sourceFiles = sourceDS.getIncludedFiles(); | |||
| for( int i = 0; upToDate && i < sourceFiles.length; i++ ) | |||
| { | |||
| File src = new File( sourceFS.getDir( project ), sourceFiles[i] ); | |||
| if( src.lastModified() > now ) | |||
| { | |||
| log( "Warning: " + sourceFiles[i] + " modified in the future.", | |||
| Project.MSG_WARN ); | |||
| } | |||
| Enumeration enumTargets = allTargets.elements(); | |||
| while( upToDate && enumTargets.hasMoreElements() ) | |||
| { | |||
| File dest = ( File )enumTargets.nextElement(); | |||
| if( src.lastModified() > dest.lastModified() ) | |||
| { | |||
| log( dest.getPath() + " is out of date with respect to " + | |||
| sourceFiles[i], Project.MSG_VERBOSE ); | |||
| upToDate = false; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| // | |||
| // Check targets vs source files specified via filelists | |||
| // | |||
| if( upToDate ) | |||
| { | |||
| Enumeration enumSourceLists = sourceFileLists.elements(); | |||
| while( upToDate && enumSourceLists.hasMoreElements() ) | |||
| { | |||
| FileList sourceFL = ( FileList )enumSourceLists.nextElement(); | |||
| String[] sourceFiles = sourceFL.getFiles( project ); | |||
| int i = 0; | |||
| do | |||
| { | |||
| File src = new File( sourceFL.getDir( project ), sourceFiles[i] ); | |||
| if( src.lastModified() > now ) | |||
| { | |||
| log( "Warning: " + sourceFiles[i] + " modified in the future.", | |||
| Project.MSG_WARN ); | |||
| } | |||
| if( !src.exists() ) | |||
| { | |||
| log( sourceFiles[i] + " does not exist.", Project.MSG_VERBOSE ); | |||
| upToDate = false; | |||
| break; | |||
| } | |||
| Enumeration enumTargets = allTargets.elements(); | |||
| while( upToDate && enumTargets.hasMoreElements() ) | |||
| { | |||
| File dest = ( File )enumTargets.nextElement(); | |||
| if( src.lastModified() > dest.lastModified() ) | |||
| { | |||
| log( dest.getPath() + " is out of date with respect to " + | |||
| sourceFiles[i], Project.MSG_VERBOSE ); | |||
| upToDate = false; | |||
| } | |||
| } | |||
| }while ( upToDate && ( ++i < sourceFiles.length ) ); | |||
| } | |||
| } | |||
| if( !upToDate ) | |||
| { | |||
| log( "Deleting all target files. ", Project.MSG_VERBOSE ); | |||
| for( Enumeration e = allTargets.elements(); e.hasMoreElements(); ) | |||
| { | |||
| File fileToRemove = ( File )e.nextElement(); | |||
| log( "Deleting file " + fileToRemove.getAbsolutePath(), Project.MSG_VERBOSE ); | |||
| fileToRemove.delete(); | |||
| } | |||
| } | |||
| }//-- execute | |||
| }//-- DependSet.java | |||
| @@ -0,0 +1,114 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.types.ZipFileSet; | |||
| import org.apache.tools.zip.ZipOutputStream; | |||
| /** | |||
| * Creates a EAR archive. Based on WAR task | |||
| * | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| * @author <a href="mailto:leslie.hughes@rubus.com">Les Hughes</a> | |||
| */ | |||
| public class Ear extends Jar | |||
| { | |||
| private File deploymentDescriptor; | |||
| private boolean descriptorAdded; | |||
| public Ear() | |||
| { | |||
| super(); | |||
| archiveType = "ear"; | |||
| emptyBehavior = "create"; | |||
| } | |||
| public void setAppxml( File descr ) | |||
| { | |||
| deploymentDescriptor = descr; | |||
| if( !deploymentDescriptor.exists() ) | |||
| throw new BuildException( "Deployment descriptor: " + deploymentDescriptor + " does not exist." ); | |||
| // Create a ZipFileSet for this file, and pass it up. | |||
| ZipFileSet fs = new ZipFileSet(); | |||
| fs.setDir( new File( deploymentDescriptor.getParent() ) ); | |||
| fs.setIncludes( deploymentDescriptor.getName() ); | |||
| fs.setFullpath( "META-INF/application.xml" ); | |||
| super.addFileset( fs ); | |||
| } | |||
| public void setEarfile( File earFile ) | |||
| { | |||
| log( "DEPRECATED - The earfile attribute is deprecated. Use file attribute instead." ); | |||
| setFile( earFile ); | |||
| } | |||
| public void addArchives( ZipFileSet fs ) | |||
| { | |||
| // We just set the prefix for this fileset, and pass it up. | |||
| // Do we need to do this? LH | |||
| log( "addArchives called", Project.MSG_DEBUG ); | |||
| fs.setPrefix( "/" ); | |||
| super.addFileset( fs ); | |||
| } | |||
| /** | |||
| * Make sure we don't think we already have a web.xml next time this task | |||
| * gets executed. | |||
| */ | |||
| protected void cleanUp() | |||
| { | |||
| descriptorAdded = false; | |||
| super.cleanUp(); | |||
| } | |||
| protected void initZipOutputStream( ZipOutputStream zOut ) | |||
| throws IOException, BuildException | |||
| { | |||
| // If no webxml file is specified, it's an error. | |||
| if( deploymentDescriptor == null && !isInUpdateMode() ) | |||
| { | |||
| throw new BuildException( "appxml attribute is required", location ); | |||
| } | |||
| super.initZipOutputStream( zOut ); | |||
| } | |||
| protected void zipFile( File file, ZipOutputStream zOut, String vPath ) | |||
| throws IOException | |||
| { | |||
| // If the file being added is WEB-INF/web.xml, we warn if it's not the | |||
| // one specified in the "webxml" attribute - or if it's being added twice, | |||
| // meaning the same file is specified by the "webxml" attribute and in | |||
| // a <fileset> element. | |||
| if( vPath.equalsIgnoreCase( "META-INF/aplication.xml" ) ) | |||
| { | |||
| if( deploymentDescriptor == null || !deploymentDescriptor.equals( file ) || descriptorAdded ) | |||
| { | |||
| log( "Warning: selected " + archiveType + " files include a META-INF/application.xml which will be ignored " + | |||
| "(please use appxml attribute to " + archiveType + " task)", Project.MSG_WARN ); | |||
| } | |||
| else | |||
| { | |||
| super.zipFile( file, zOut, vPath ); | |||
| descriptorAdded = true; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| super.zipFile( file, zOut, vPath ); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,159 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.File; | |||
| import java.io.FileWriter; | |||
| import java.io.IOException; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.ProjectHelper; | |||
| import org.apache.tools.ant.Task; | |||
| import org.apache.tools.ant.types.EnumeratedAttribute; | |||
| /** | |||
| * Echo | |||
| * | |||
| * @author costin@dnt.ro | |||
| */ | |||
| public class Echo extends Task | |||
| { | |||
| protected String message = "";// required | |||
| protected File file = null; | |||
| protected boolean append = false; | |||
| // by default, messages are always displayed | |||
| protected int logLevel = Project.MSG_WARN; | |||
| /** | |||
| * Shall we append to an existing file? | |||
| * | |||
| * @param append The new Append value | |||
| */ | |||
| public void setAppend( boolean append ) | |||
| { | |||
| this.append = append; | |||
| } | |||
| /** | |||
| * Sets the file attribute. | |||
| * | |||
| * @param file The new File value | |||
| */ | |||
| public void setFile( File file ) | |||
| { | |||
| this.file = file; | |||
| } | |||
| /** | |||
| * Set the logging level to one of | |||
| * <ul> | |||
| * <li> error</li> | |||
| * <li> warning</li> | |||
| * <li> info</li> | |||
| * <li> verbose</li> | |||
| * <li> debug</li> | |||
| * <ul><p> | |||
| * | |||
| * The default is "warning" to ensure that messages are | |||
| * displayed by default when using the -quiet command line option.</p> | |||
| * | |||
| * @param echoLevel The new Level value | |||
| */ | |||
| public void setLevel( EchoLevel echoLevel ) | |||
| { | |||
| String option = echoLevel.getValue(); | |||
| if( option.equals( "error" ) ) | |||
| { | |||
| logLevel = Project.MSG_ERR; | |||
| } | |||
| else if( option.equals( "warning" ) ) | |||
| { | |||
| logLevel = Project.MSG_WARN; | |||
| } | |||
| else if( option.equals( "info" ) ) | |||
| { | |||
| logLevel = Project.MSG_INFO; | |||
| } | |||
| else if( option.equals( "verbose" ) ) | |||
| { | |||
| logLevel = Project.MSG_VERBOSE; | |||
| } | |||
| else | |||
| { | |||
| // must be "debug" | |||
| logLevel = Project.MSG_DEBUG; | |||
| } | |||
| } | |||
| /** | |||
| * Sets the message variable. | |||
| * | |||
| * @param msg Sets the value for the message variable. | |||
| */ | |||
| public void setMessage( String msg ) | |||
| { | |||
| this.message = msg; | |||
| } | |||
| /** | |||
| * Set a multiline message. | |||
| * | |||
| * @param msg The feature to be added to the Text attribute | |||
| */ | |||
| public void addText( String msg ) | |||
| { | |||
| message += project.replaceProperties( msg ); | |||
| } | |||
| /** | |||
| * Does the work. | |||
| * | |||
| * @exception BuildException if someting goes wrong with the build | |||
| */ | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| if( file == null ) | |||
| { | |||
| log( message, logLevel ); | |||
| } | |||
| else | |||
| { | |||
| FileWriter out = null; | |||
| try | |||
| { | |||
| out = new FileWriter( file.getAbsolutePath(), append ); | |||
| out.write( message, 0, message.length() ); | |||
| } | |||
| catch( IOException ioe ) | |||
| { | |||
| throw new BuildException( ioe); | |||
| } | |||
| finally | |||
| { | |||
| if( out != null ) | |||
| { | |||
| try | |||
| { | |||
| out.close(); | |||
| } | |||
| catch( IOException ioex ) | |||
| {} | |||
| } | |||
| } | |||
| } | |||
| } | |||
| public static class EchoLevel extends EnumeratedAttribute | |||
| { | |||
| public String[] getValues() | |||
| { | |||
| return new String[]{"error", "warning", "info", "verbose", "debug"}; | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,252 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.BufferedReader; | |||
| import java.io.File; | |||
| import java.io.FileWriter; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.io.InputStreamReader; | |||
| import java.io.PrintWriter; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.Task; | |||
| /** | |||
| * Executes a given command if the os platform is appropriate. | |||
| * | |||
| * @author duncan@x180.com | |||
| * @author rubys@us.ibm.com | |||
| * @deprecated Instead of using this class, please extend ExecTask or delegate | |||
| * to Execute. | |||
| */ | |||
| public class Exec extends Task | |||
| { | |||
| private final static int BUFFER_SIZE = 512; | |||
| protected PrintWriter fos = null; | |||
| private boolean failOnError = false; | |||
| private String command; | |||
| private File dir; | |||
| private String os; | |||
| private String out; | |||
| public void setCommand( String command ) | |||
| { | |||
| this.command = command; | |||
| } | |||
| public void setDir( String d ) | |||
| { | |||
| this.dir = project.resolveFile( d ); | |||
| } | |||
| public void setFailonerror( boolean fail ) | |||
| { | |||
| failOnError = fail; | |||
| } | |||
| public void setOs( String os ) | |||
| { | |||
| this.os = os; | |||
| } | |||
| public void setOutput( String out ) | |||
| { | |||
| this.out = out; | |||
| } | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| run( command ); | |||
| } | |||
| protected void logFlush() | |||
| { | |||
| if( fos != null ) | |||
| fos.close(); | |||
| } | |||
| protected void outputLog( String line, int messageLevel ) | |||
| { | |||
| if( fos == null ) | |||
| { | |||
| log( line, messageLevel ); | |||
| } | |||
| else | |||
| { | |||
| fos.println( line ); | |||
| } | |||
| } | |||
| protected int run( String command ) | |||
| throws BuildException | |||
| { | |||
| int err = -1;// assume the worst | |||
| // test if os match | |||
| String myos = System.getProperty( "os.name" ); | |||
| log( "Myos = " + myos, Project.MSG_VERBOSE ); | |||
| if( ( os != null ) && ( os.indexOf( myos ) < 0 ) ) | |||
| { | |||
| // this command will be executed only on the specified OS | |||
| log( "Not found in " + os, Project.MSG_VERBOSE ); | |||
| return 0; | |||
| } | |||
| // default directory to the project's base directory | |||
| if( dir == null ) | |||
| dir = project.getBaseDir(); | |||
| if( myos.toLowerCase().indexOf( "windows" ) >= 0 ) | |||
| { | |||
| if( !dir.equals( project.resolveFile( "." ) ) ) | |||
| { | |||
| if( myos.toLowerCase().indexOf( "nt" ) >= 0 ) | |||
| { | |||
| command = "cmd /c cd " + dir + " && " + command; | |||
| } | |||
| else | |||
| { | |||
| String ant = project.getProperty( "ant.home" ); | |||
| if( ant == null ) | |||
| { | |||
| throw new BuildException( "Property 'ant.home' not found", location ); | |||
| } | |||
| String antRun = project.resolveFile( ant + "/bin/antRun.bat" ).toString(); | |||
| command = antRun + " " + dir + " " + command; | |||
| } | |||
| } | |||
| } | |||
| else | |||
| { | |||
| String ant = project.getProperty( "ant.home" ); | |||
| if( ant == null ) | |||
| throw new BuildException( "Property 'ant.home' not found", location ); | |||
| String antRun = project.resolveFile( ant + "/bin/antRun" ).toString(); | |||
| command = antRun + " " + dir + " " + command; | |||
| } | |||
| try | |||
| { | |||
| // show the command | |||
| log( command, Project.MSG_VERBOSE ); | |||
| // exec command on system runtime | |||
| Process proc = Runtime.getRuntime().exec( command ); | |||
| if( out != null ) | |||
| { | |||
| fos = new PrintWriter( new FileWriter( out ) ); | |||
| log( "Output redirected to " + out, Project.MSG_VERBOSE ); | |||
| } | |||
| // copy input and error to the output stream | |||
| StreamPumper inputPumper = | |||
| new StreamPumper( proc.getInputStream(), Project.MSG_INFO, this ); | |||
| StreamPumper errorPumper = | |||
| new StreamPumper( proc.getErrorStream(), Project.MSG_WARN, this ); | |||
| // starts pumping away the generated output/error | |||
| inputPumper.start(); | |||
| errorPumper.start(); | |||
| // Wait for everything to finish | |||
| proc.waitFor(); | |||
| inputPumper.join(); | |||
| errorPumper.join(); | |||
| proc.destroy(); | |||
| // close the output file if required | |||
| logFlush(); | |||
| // check its exit value | |||
| err = proc.exitValue(); | |||
| if( err != 0 ) | |||
| { | |||
| if( failOnError ) | |||
| { | |||
| throw new BuildException( "Exec returned: " + err, location ); | |||
| } | |||
| else | |||
| { | |||
| log( "Result: " + err, Project.MSG_ERR ); | |||
| } | |||
| } | |||
| } | |||
| catch( IOException ioe ) | |||
| { | |||
| throw new BuildException( "Error exec: " + command, ioe, location ); | |||
| } | |||
| catch( InterruptedException ex ) | |||
| {} | |||
| return err; | |||
| } | |||
| // Inner class for continually pumping the input stream during | |||
| // Process's runtime. | |||
| class StreamPumper extends Thread | |||
| { | |||
| private boolean endOfStream = false; | |||
| private int SLEEP_TIME = 5; | |||
| private BufferedReader din; | |||
| private int messageLevel; | |||
| private Exec parent; | |||
| public StreamPumper( InputStream is, int messageLevel, Exec parent ) | |||
| { | |||
| this.din = new BufferedReader( new InputStreamReader( is ) ); | |||
| this.messageLevel = messageLevel; | |||
| this.parent = parent; | |||
| } | |||
| public void pumpStream() | |||
| throws IOException | |||
| { | |||
| byte[] buf = new byte[BUFFER_SIZE]; | |||
| if( !endOfStream ) | |||
| { | |||
| String line = din.readLine(); | |||
| if( line != null ) | |||
| { | |||
| outputLog( line, messageLevel ); | |||
| } | |||
| else | |||
| { | |||
| endOfStream = true; | |||
| } | |||
| } | |||
| } | |||
| public void run() | |||
| { | |||
| try | |||
| { | |||
| try | |||
| { | |||
| while( !endOfStream ) | |||
| { | |||
| pumpStream(); | |||
| sleep( SLEEP_TIME ); | |||
| } | |||
| } | |||
| catch( InterruptedException ie ) | |||
| {} | |||
| din.close(); | |||
| } | |||
| catch( IOException ioe ) | |||
| {} | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,456 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.BufferedReader; | |||
| import java.io.ByteArrayOutputStream; | |||
| import java.io.File; | |||
| import java.io.FileNotFoundException; | |||
| import java.io.FileOutputStream; | |||
| import java.io.IOException; | |||
| import java.io.StringReader; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.Task; | |||
| import org.apache.tools.ant.types.Commandline; | |||
| import org.apache.tools.ant.types.Environment; | |||
| /** | |||
| * Executes a given command if the os platform is appropriate. | |||
| * | |||
| * @author duncan@x180.com | |||
| * @author rubys@us.ibm.com | |||
| * @author thomas.haas@softwired-inc.com | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| * @author <a href="mailto:mariusz@rakiura.org">Mariusz Nowostawski</a> | |||
| */ | |||
| public class ExecTask extends Task | |||
| { | |||
| private static String lSep = System.getProperty( "line.separator" ); | |||
| protected boolean failOnError = false; | |||
| protected boolean newEnvironment = false; | |||
| private Integer timeout = null; | |||
| private Environment env = new Environment(); | |||
| protected Commandline cmdl = new Commandline(); | |||
| private FileOutputStream fos = null; | |||
| private ByteArrayOutputStream baos = null; | |||
| private boolean failIfExecFails = true; | |||
| /** | |||
| * Controls whether the VM (1.3 and above) is used to execute the command | |||
| */ | |||
| private boolean vmLauncher = true; | |||
| private File dir; | |||
| private String os; | |||
| private File out; | |||
| private String outputprop; | |||
| private String resultProperty; | |||
| /** | |||
| * The full commandline to execute, executable + arguments. | |||
| * | |||
| * @param cmdl The new Command value | |||
| */ | |||
| public void setCommand( Commandline cmdl ) | |||
| { | |||
| log( "The command attribute is deprecated. " + | |||
| "Please use the executable attribute and nested arg elements.", | |||
| Project.MSG_WARN ); | |||
| this.cmdl = cmdl; | |||
| } | |||
| /** | |||
| * The working directory of the process | |||
| * | |||
| * @param d The new Dir value | |||
| */ | |||
| public void setDir( File d ) | |||
| { | |||
| this.dir = d; | |||
| } | |||
| /** | |||
| * The command to execute. | |||
| * | |||
| * @param value The new Executable value | |||
| */ | |||
| public void setExecutable( String value ) | |||
| { | |||
| cmdl.setExecutable( value ); | |||
| } | |||
| /** | |||
| * ant attribute | |||
| * | |||
| * @param flag The new FailIfExecutionFails value | |||
| */ | |||
| public void setFailIfExecutionFails( boolean flag ) | |||
| { | |||
| failIfExecFails = flag; | |||
| } | |||
| /** | |||
| * Throw a BuildException if process returns non 0. | |||
| * | |||
| * @param fail The new Failonerror value | |||
| */ | |||
| public void setFailonerror( boolean fail ) | |||
| { | |||
| failOnError = fail; | |||
| } | |||
| /** | |||
| * Use a completely new environment | |||
| * | |||
| * @param newenv The new Newenvironment value | |||
| */ | |||
| public void setNewenvironment( boolean newenv ) | |||
| { | |||
| newEnvironment = newenv; | |||
| } | |||
| /** | |||
| * Only execute the process if <code>os.name</code> is included in this | |||
| * string. | |||
| * | |||
| * @param os The new Os value | |||
| */ | |||
| public void setOs( String os ) | |||
| { | |||
| this.os = os; | |||
| } | |||
| /** | |||
| * File the output of the process is redirected to. | |||
| * | |||
| * @param out The new Output value | |||
| */ | |||
| public void setOutput( File out ) | |||
| { | |||
| this.out = out; | |||
| } | |||
| /** | |||
| * Property name whose value should be set to the output of the process | |||
| * | |||
| * @param outputprop The new Outputproperty value | |||
| */ | |||
| public void setOutputproperty( String outputprop ) | |||
| { | |||
| this.outputprop = outputprop; | |||
| } | |||
| /** | |||
| * fill a property in with a result. when no property is defined: failure to | |||
| * execute | |||
| * | |||
| * @param resultProperty The new ResultProperty value | |||
| * @since 1.5 | |||
| */ | |||
| public void setResultProperty( String resultProperty ) | |||
| { | |||
| this.resultProperty = resultProperty; | |||
| } | |||
| /** | |||
| * Timeout in milliseconds after which the process will be killed. | |||
| * | |||
| * @param value The new Timeout value | |||
| */ | |||
| public void setTimeout( Integer value ) | |||
| { | |||
| timeout = value; | |||
| } | |||
| /** | |||
| * Control whether the VM is used to launch the new process or whether the | |||
| * OS's shell is used. | |||
| * | |||
| * @param vmLauncher The new VMLauncher value | |||
| */ | |||
| public void setVMLauncher( boolean vmLauncher ) | |||
| { | |||
| this.vmLauncher = vmLauncher; | |||
| } | |||
| /** | |||
| * Add a nested env element - an environment variable. | |||
| * | |||
| * @param var The feature to be added to the Env attribute | |||
| */ | |||
| public void addEnv( Environment.Variable var ) | |||
| { | |||
| env.addVariable( var ); | |||
| } | |||
| /** | |||
| * Add a nested arg element - a command line argument. | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public Commandline.Argument createArg() | |||
| { | |||
| return cmdl.createArgument(); | |||
| } | |||
| /** | |||
| * Do the work. | |||
| * | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| checkConfiguration(); | |||
| if( isValidOs() ) | |||
| { | |||
| runExec( prepareExec() ); | |||
| } | |||
| } | |||
| /** | |||
| * Is this the OS the user wanted? | |||
| * | |||
| * @return The ValidOs value | |||
| */ | |||
| protected boolean isValidOs() | |||
| { | |||
| // test if os match | |||
| String myos = System.getProperty( "os.name" ); | |||
| log( "Current OS is " + myos, Project.MSG_VERBOSE ); | |||
| if( ( os != null ) && ( os.indexOf( myos ) < 0 ) ) | |||
| { | |||
| // this command will be executed only on the specified OS | |||
| log( "This OS, " + myos + " was not found in the specified list of valid OSes: " + os, Project.MSG_VERBOSE ); | |||
| return false; | |||
| } | |||
| return true; | |||
| } | |||
| /** | |||
| * A Utility method for this classes and subclasses to run an Execute | |||
| * instance (an external command). | |||
| * | |||
| * @param exe Description of Parameter | |||
| * @exception IOException Description of Exception | |||
| */ | |||
| protected final void runExecute( Execute exe ) | |||
| throws IOException | |||
| { | |||
| int err = -1;// assume the worst | |||
| err = exe.execute(); | |||
| //test for and handle a forced process death | |||
| if( exe.killedProcess() ) | |||
| { | |||
| log( "Timeout: killed the sub-process", Project.MSG_WARN ); | |||
| } | |||
| maybeSetResultPropertyValue( err ); | |||
| if( err != 0 ) | |||
| { | |||
| if( failOnError ) | |||
| { | |||
| throw new BuildException( taskType + " returned: " + err, location ); | |||
| } | |||
| else | |||
| { | |||
| log( "Result: " + err, Project.MSG_ERR ); | |||
| } | |||
| } | |||
| if( baos != null ) | |||
| { | |||
| BufferedReader in = | |||
| new BufferedReader( new StringReader( baos.toString() ) ); | |||
| String line = null; | |||
| StringBuffer val = new StringBuffer(); | |||
| while( ( line = in.readLine() ) != null ) | |||
| { | |||
| if( val.length() != 0 ) | |||
| { | |||
| val.append( lSep ); | |||
| } | |||
| val.append( line ); | |||
| } | |||
| project.setNewProperty( outputprop, val.toString() ); | |||
| } | |||
| } | |||
| /** | |||
| * Has the user set all necessary attributes? | |||
| * | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| protected void checkConfiguration() | |||
| throws BuildException | |||
| { | |||
| if( cmdl.getExecutable() == null ) | |||
| { | |||
| throw new BuildException( "no executable specified", location ); | |||
| } | |||
| if( dir != null && !dir.exists() ) | |||
| { | |||
| throw new BuildException( "The directory you specified does not exist" ); | |||
| } | |||
| if( dir != null && !dir.isDirectory() ) | |||
| { | |||
| throw new BuildException( "The directory you specified is not a directory" ); | |||
| } | |||
| } | |||
| /** | |||
| * Create the StreamHandler to use with our Execute instance. | |||
| * | |||
| * @return Description of the Returned Value | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| protected ExecuteStreamHandler createHandler() | |||
| throws BuildException | |||
| { | |||
| if( out != null ) | |||
| { | |||
| try | |||
| { | |||
| fos = new FileOutputStream( out ); | |||
| log( "Output redirected to " + out, Project.MSG_VERBOSE ); | |||
| return new PumpStreamHandler( fos ); | |||
| } | |||
| catch( FileNotFoundException fne ) | |||
| { | |||
| throw new BuildException( "Cannot write to " + out, fne, location ); | |||
| } | |||
| catch( IOException ioe ) | |||
| { | |||
| throw new BuildException( "Cannot write to " + out, ioe, location ); | |||
| } | |||
| } | |||
| else if( outputprop != null ) | |||
| { | |||
| baos = new ByteArrayOutputStream(); | |||
| log( "Output redirected to ByteArray", Project.MSG_VERBOSE ); | |||
| return new PumpStreamHandler( baos ); | |||
| } | |||
| else | |||
| { | |||
| return new LogStreamHandler( this, | |||
| Project.MSG_INFO, Project.MSG_WARN ); | |||
| } | |||
| } | |||
| /** | |||
| * Create the Watchdog to kill a runaway process. | |||
| * | |||
| * @return Description of the Returned Value | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| protected ExecuteWatchdog createWatchdog() | |||
| throws BuildException | |||
| { | |||
| if( timeout == null ) | |||
| return null; | |||
| return new ExecuteWatchdog( timeout.intValue() ); | |||
| } | |||
| /** | |||
| * Flush the output stream - if there is one. | |||
| */ | |||
| protected void logFlush() | |||
| { | |||
| try | |||
| { | |||
| if( fos != null ) | |||
| fos.close(); | |||
| if( baos != null ) | |||
| baos.close(); | |||
| } | |||
| catch( IOException io ) | |||
| {} | |||
| } | |||
| /** | |||
| * helper method to set result property to the passed in value if | |||
| * appropriate | |||
| * | |||
| * @param result Description of Parameter | |||
| */ | |||
| protected void maybeSetResultPropertyValue( int result ) | |||
| { | |||
| String res = Integer.toString( result ); | |||
| if( resultProperty != null ) | |||
| { | |||
| project.setNewProperty( resultProperty, res ); | |||
| } | |||
| } | |||
| /** | |||
| * Create an Execute instance with the correct working directory set. | |||
| * | |||
| * @return Description of the Returned Value | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| protected Execute prepareExec() | |||
| throws BuildException | |||
| { | |||
| // default directory to the project's base directory | |||
| if( dir == null ) | |||
| dir = project.getBaseDir(); | |||
| // show the command | |||
| log( cmdl.toString(), Project.MSG_VERBOSE ); | |||
| Execute exe = new Execute( createHandler(), createWatchdog() ); | |||
| exe.setAntRun( project ); | |||
| exe.setWorkingDirectory( dir ); | |||
| exe.setVMLauncher( vmLauncher ); | |||
| String[] environment = env.getVariables(); | |||
| if( environment != null ) | |||
| { | |||
| for( int i = 0; i < environment.length; i++ ) | |||
| { | |||
| log( "Setting environment variable: " + environment[i], | |||
| Project.MSG_VERBOSE ); | |||
| } | |||
| } | |||
| exe.setNewenvironment( newEnvironment ); | |||
| exe.setEnvironment( environment ); | |||
| return exe; | |||
| } | |||
| /** | |||
| * Run the command using the given Execute instance. This may be overidden | |||
| * by subclasses | |||
| * | |||
| * @param exe Description of Parameter | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| protected void runExec( Execute exe ) | |||
| throws BuildException | |||
| { | |||
| exe.setCommandline( cmdl.getCommandline() ); | |||
| try | |||
| { | |||
| runExecute( exe ); | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| if( failIfExecFails ) | |||
| { | |||
| throw new BuildException( "Execute failed: " + e.toString(), e, location ); | |||
| } | |||
| else | |||
| { | |||
| log( "Execute failed: " + e.toString(), Project.MSG_ERR ); | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| // close the output file if required | |||
| logFlush(); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,947 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.BufferedReader; | |||
| import java.io.ByteArrayOutputStream; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| import java.io.StringReader; | |||
| import java.lang.reflect.InvocationTargetException; | |||
| import java.lang.reflect.Method; | |||
| import java.util.Locale; | |||
| import java.util.Vector; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.Task; | |||
| import org.apache.myrmidon.framework.Os; | |||
| import org.apache.tools.ant.types.Commandline; | |||
| /** | |||
| * Runs an external program. | |||
| * | |||
| * @author thomas.haas@softwired-inc.com | |||
| */ | |||
| public class Execute | |||
| { | |||
| /** | |||
| * Invalid exit code. | |||
| */ | |||
| public final static int INVALID = Integer.MAX_VALUE; | |||
| private static String antWorkingDirectory = System.getProperty( "user.dir" ); | |||
| private static CommandLauncher vmLauncher; | |||
| private static CommandLauncher shellLauncher; | |||
| private static Vector procEnvironment; | |||
| /** | |||
| * Used to destroy processes when the VM exits. | |||
| */ | |||
| private static ProcessDestroyer processDestroyer = new ProcessDestroyer(); | |||
| private String[] cmdl = null; | |||
| private String[] env = null; | |||
| private int exitValue = INVALID; | |||
| private File workingDirectory = null; | |||
| private Project project = null; | |||
| private boolean newEnvironment = false; | |||
| /** | |||
| * Controls whether the VM is used to launch commands, where possible | |||
| */ | |||
| private boolean useVMLauncher = true; | |||
| private ExecuteStreamHandler streamHandler; | |||
| private ExecuteWatchdog watchdog; | |||
| /** | |||
| * Builds a command launcher for the OS and JVM we are running under | |||
| */ | |||
| static | |||
| { | |||
| // Try using a JDK 1.3 launcher | |||
| try | |||
| { | |||
| vmLauncher = new Java13CommandLauncher(); | |||
| } | |||
| catch( NoSuchMethodException exc ) | |||
| { | |||
| // Ignore and keep try | |||
| } | |||
| if( Os.isFamily( "mac" ) ) | |||
| { | |||
| // Mac | |||
| shellLauncher = new MacCommandLauncher( new CommandLauncher() ); | |||
| } | |||
| else if( Os.isFamily( "os/2" ) ) | |||
| { | |||
| // OS/2 - use same mechanism as Windows 2000 | |||
| shellLauncher = new WinNTCommandLauncher( new CommandLauncher() ); | |||
| } | |||
| else if( Os.isFamily( "windows" ) ) | |||
| { | |||
| // Windows. Need to determine which JDK we're running in | |||
| CommandLauncher baseLauncher; | |||
| if( System.getProperty( "java.version" ).startsWith( "1.1" ) ) | |||
| { | |||
| // JDK 1.1 | |||
| baseLauncher = new Java11CommandLauncher(); | |||
| } | |||
| else | |||
| { | |||
| // JDK 1.2 | |||
| baseLauncher = new CommandLauncher(); | |||
| } | |||
| // Determine if we're running under 2000/NT or 98/95 | |||
| String osname = | |||
| System.getProperty( "os.name" ).toLowerCase( Locale.US ); | |||
| if( osname.indexOf( "nt" ) >= 0 || osname.indexOf( "2000" ) >= 0 ) | |||
| { | |||
| // Windows 2000/NT | |||
| shellLauncher = new WinNTCommandLauncher( baseLauncher ); | |||
| } | |||
| else | |||
| { | |||
| // Windows 98/95 - need to use an auxiliary script | |||
| shellLauncher = new ScriptCommandLauncher( "bin/antRun.bat", baseLauncher ); | |||
| } | |||
| } | |||
| else if( ( new Os( "netware" ) ).eval() ) | |||
| { | |||
| // NetWare. Need to determine which JDK we're running in | |||
| CommandLauncher baseLauncher; | |||
| if( System.getProperty( "java.version" ).startsWith( "1.1" ) ) | |||
| { | |||
| // JDK 1.1 | |||
| baseLauncher = new Java11CommandLauncher(); | |||
| } | |||
| else | |||
| { | |||
| // JDK 1.2 | |||
| baseLauncher = new CommandLauncher(); | |||
| } | |||
| shellLauncher = new PerlScriptCommandLauncher( "bin/antRun.pl", baseLauncher ); | |||
| } | |||
| else | |||
| { | |||
| // Generic | |||
| shellLauncher = new ScriptCommandLauncher( "bin/antRun", new CommandLauncher() ); | |||
| } | |||
| } | |||
| /** | |||
| * Creates a new execute object using <code>PumpStreamHandler</code> for | |||
| * stream handling. | |||
| */ | |||
| public Execute() | |||
| { | |||
| this( new PumpStreamHandler(), null ); | |||
| } | |||
| /** | |||
| * Creates a new execute object. | |||
| * | |||
| * @param streamHandler the stream handler used to handle the input and | |||
| * output streams of the subprocess. | |||
| */ | |||
| public Execute( ExecuteStreamHandler streamHandler ) | |||
| { | |||
| this( streamHandler, null ); | |||
| } | |||
| /** | |||
| * Creates a new execute object. | |||
| * | |||
| * @param streamHandler the stream handler used to handle the input and | |||
| * output streams of the subprocess. | |||
| * @param watchdog a watchdog for the subprocess or <code>null</code> to to | |||
| * disable a timeout for the subprocess. | |||
| */ | |||
| public Execute( ExecuteStreamHandler streamHandler, ExecuteWatchdog watchdog ) | |||
| { | |||
| this.streamHandler = streamHandler; | |||
| this.watchdog = watchdog; | |||
| } | |||
| /** | |||
| * Find the list of environment variables for this process. | |||
| * | |||
| * @return The ProcEnvironment value | |||
| */ | |||
| public static synchronized Vector getProcEnvironment() | |||
| { | |||
| if( procEnvironment != null ) | |||
| return procEnvironment; | |||
| procEnvironment = new Vector(); | |||
| try | |||
| { | |||
| ByteArrayOutputStream out = new ByteArrayOutputStream(); | |||
| Execute exe = new Execute( new PumpStreamHandler( out ) ); | |||
| exe.setCommandline( getProcEnvCommand() ); | |||
| // Make sure we do not recurse forever | |||
| exe.setNewenvironment( true ); | |||
| int retval = exe.execute(); | |||
| if( retval != 0 ) | |||
| { | |||
| // Just try to use what we got | |||
| } | |||
| BufferedReader in = | |||
| new BufferedReader( new StringReader( out.toString() ) ); | |||
| String var = null; | |||
| String line; | |||
| String lineSep = System.getProperty( "line.separator" ); | |||
| while( ( line = in.readLine() ) != null ) | |||
| { | |||
| if( line.indexOf( '=' ) == -1 ) | |||
| { | |||
| // Chunk part of previous env var (UNIX env vars can | |||
| // contain embedded new lines). | |||
| if( var == null ) | |||
| { | |||
| var = lineSep + line; | |||
| } | |||
| else | |||
| { | |||
| var += lineSep + line; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| // New env var...append the previous one if we have it. | |||
| if( var != null ) | |||
| { | |||
| procEnvironment.addElement( var ); | |||
| } | |||
| var = line; | |||
| } | |||
| } | |||
| // Since we "look ahead" before adding, there's one last env var. | |||
| procEnvironment.addElement( var ); | |||
| } | |||
| catch( java.io.IOException exc ) | |||
| { | |||
| exc.printStackTrace(); | |||
| // Just try to see how much we got | |||
| } | |||
| return procEnvironment; | |||
| } | |||
| /** | |||
| * A utility method that runs an external command. Writes the output and | |||
| * error streams of the command to the project log. | |||
| * | |||
| * @param task The task that the command is part of. Used for logging | |||
| * @param cmdline The command to execute. | |||
| * @throws BuildException if the command does not return 0. | |||
| */ | |||
| public static void runCommand( Task task, String[] cmdline ) | |||
| throws BuildException | |||
| { | |||
| try | |||
| { | |||
| task.log( Commandline.toString( cmdline ), Project.MSG_VERBOSE ); | |||
| Execute exe = new Execute( new LogStreamHandler( task, | |||
| Project.MSG_INFO, | |||
| Project.MSG_ERR ) ); | |||
| exe.setAntRun( task.getProject() ); | |||
| exe.setCommandline( cmdline ); | |||
| int retval = exe.execute(); | |||
| if( retval != 0 ) | |||
| { | |||
| throw new BuildException( cmdline[ 0 ] + " failed with return code " + retval, task.getLocation() ); | |||
| } | |||
| } | |||
| catch( java.io.IOException exc ) | |||
| { | |||
| throw new BuildException( "Could not launch " + cmdline[ 0 ] + ": " + exc, task.getLocation() ); | |||
| } | |||
| } | |||
| private static String[] getProcEnvCommand() | |||
| { | |||
| if( Os.isFamily( "os/2" ) ) | |||
| { | |||
| // OS/2 - use same mechanism as Windows 2000 | |||
| // Not sure | |||
| String[] cmd = {"cmd", "/c", "set"}; | |||
| return cmd; | |||
| } | |||
| else if( Os.isFamily( "windows" ) ) | |||
| { | |||
| String osname = | |||
| System.getProperty( "os.name" ).toLowerCase( Locale.US ); | |||
| // Determine if we're running under 2000/NT or 98/95 | |||
| if( osname.indexOf( "nt" ) >= 0 || osname.indexOf( "2000" ) >= 0 ) | |||
| { | |||
| // Windows 2000/NT | |||
| String[] cmd = {"cmd", "/c", "set"}; | |||
| return cmd; | |||
| } | |||
| else | |||
| { | |||
| // Windows 98/95 - need to use an auxiliary script | |||
| String[] cmd = {"command.com", "/c", "set"}; | |||
| return cmd; | |||
| } | |||
| } | |||
| else if( Os.isFamily( "unix" ) ) | |||
| { | |||
| // Generic UNIX | |||
| // Alternatively one could use: /bin/sh -c env | |||
| String[] cmd = {"/usr/bin/env"}; | |||
| return cmd; | |||
| } | |||
| else if( Os.isFamily( "netware" ) ) | |||
| { | |||
| String[] cmd = {"env"}; | |||
| return cmd; | |||
| } | |||
| else | |||
| { | |||
| // MAC OS 9 and previous | |||
| // TODO: I have no idea how to get it, someone must fix it | |||
| String[] cmd = null; | |||
| return cmd; | |||
| } | |||
| } | |||
| /** | |||
| * Set the name of the antRun script using the project's value. | |||
| * | |||
| * @param project the current project. | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| public void setAntRun( Project project ) | |||
| throws BuildException | |||
| { | |||
| this.project = project; | |||
| } | |||
| /** | |||
| * Sets the commandline of the subprocess to launch. | |||
| * | |||
| * @param commandline the commandline of the subprocess to launch | |||
| */ | |||
| public void setCommandline( String[] commandline ) | |||
| { | |||
| cmdl = commandline; | |||
| } | |||
| /** | |||
| * Sets the environment variables for the subprocess to launch. | |||
| * | |||
| * @param env The new Environment value | |||
| */ | |||
| public void setEnvironment( String[] env ) | |||
| { | |||
| this.env = env; | |||
| } | |||
| /** | |||
| * Set whether to propagate the default environment or not. | |||
| * | |||
| * @param newenv whether to propagate the process environment. | |||
| */ | |||
| public void setNewenvironment( boolean newenv ) | |||
| { | |||
| newEnvironment = newenv; | |||
| } | |||
| /** | |||
| * Launch this execution through the VM, where possible, rather than through | |||
| * the OS's shell. In some cases and operating systems using the shell will | |||
| * allow the shell to perform additional processing such as associating an | |||
| * executable with a script, etc | |||
| * | |||
| * @param useVMLauncher The new VMLauncher value | |||
| */ | |||
| public void setVMLauncher( boolean useVMLauncher ) | |||
| { | |||
| this.useVMLauncher = useVMLauncher; | |||
| } | |||
| /** | |||
| * Sets the working directory of the process to execute. <p> | |||
| * | |||
| * This is emulated using the antRun scripts unless the OS is Windows NT in | |||
| * which case a cmd.exe is spawned, or MRJ and setting user.dir works, or | |||
| * JDK 1.3 and there is official support in java.lang.Runtime. | |||
| * | |||
| * @param wd the working directory of the process. | |||
| */ | |||
| public void setWorkingDirectory( File wd ) | |||
| { | |||
| if( wd == null || wd.getAbsolutePath().equals( antWorkingDirectory ) ) | |||
| workingDirectory = null; | |||
| else | |||
| workingDirectory = wd; | |||
| } | |||
| /** | |||
| * Returns the commandline used to create a subprocess. | |||
| * | |||
| * @return the commandline used to create a subprocess | |||
| */ | |||
| public String[] getCommandline() | |||
| { | |||
| return cmdl; | |||
| } | |||
| /** | |||
| * Returns the environment used to create a subprocess. | |||
| * | |||
| * @return the environment used to create a subprocess | |||
| */ | |||
| public String[] getEnvironment() | |||
| { | |||
| if( env == null || newEnvironment ) | |||
| return env; | |||
| return patchEnvironment(); | |||
| } | |||
| /** | |||
| * query the exit value of the process. | |||
| * | |||
| * @return the exit value, 1 if the process was killed, or Project.INVALID | |||
| * if no exit value has been received | |||
| */ | |||
| public int getExitValue() | |||
| { | |||
| return exitValue; | |||
| } | |||
| /** | |||
| * Runs a process defined by the command line and returns its exit status. | |||
| * | |||
| * @return the exit status of the subprocess or <code>INVALID</code> | |||
| * @exception IOException Description of Exception | |||
| */ | |||
| public int execute() | |||
| throws IOException | |||
| { | |||
| CommandLauncher launcher = vmLauncher != null ? vmLauncher : shellLauncher; | |||
| if( !useVMLauncher ) | |||
| { | |||
| launcher = shellLauncher; | |||
| } | |||
| final Process process = launcher.exec( project, getCommandline(), getEnvironment(), workingDirectory ); | |||
| try | |||
| { | |||
| streamHandler.setProcessInputStream( process.getOutputStream() ); | |||
| streamHandler.setProcessOutputStream( process.getInputStream() ); | |||
| streamHandler.setProcessErrorStream( process.getErrorStream() ); | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| process.destroy(); | |||
| throw e; | |||
| } | |||
| streamHandler.start(); | |||
| // add the process to the list of those to destroy if the VM exits | |||
| // | |||
| processDestroyer.add( process ); | |||
| if( watchdog != null ) | |||
| watchdog.start( process ); | |||
| waitFor( process ); | |||
| // remove the process to the list of those to destroy if the VM exits | |||
| // | |||
| processDestroyer.remove( process ); | |||
| if( watchdog != null ) | |||
| watchdog.stop(); | |||
| streamHandler.stop(); | |||
| if( watchdog != null ) | |||
| watchdog.checkException(); | |||
| return getExitValue(); | |||
| } | |||
| /** | |||
| * test for an untimely death of the process | |||
| * | |||
| * @return true iff a watchdog had to kill the process | |||
| * @since 1.5 | |||
| */ | |||
| public boolean killedProcess() | |||
| { | |||
| return watchdog != null && watchdog.killedProcess(); | |||
| } | |||
| protected void setExitValue( int value ) | |||
| { | |||
| exitValue = value; | |||
| } | |||
| protected void waitFor( Process process ) | |||
| { | |||
| try | |||
| { | |||
| process.waitFor(); | |||
| setExitValue( process.exitValue() ); | |||
| } | |||
| catch( InterruptedException e ) | |||
| { | |||
| } | |||
| } | |||
| /** | |||
| * Patch the current environment with the new values from the user. | |||
| * | |||
| * @return the patched environment | |||
| */ | |||
| private String[] patchEnvironment() | |||
| { | |||
| Vector osEnv = (Vector)getProcEnvironment().clone(); | |||
| for( int i = 0; i < env.length; i++ ) | |||
| { | |||
| int pos = env[ i ].indexOf( '=' ); | |||
| // Get key including "=" | |||
| String key = env[ i ].substring( 0, pos + 1 ); | |||
| int size = osEnv.size(); | |||
| for( int j = 0; j < size; j++ ) | |||
| { | |||
| if( ( (String)osEnv.elementAt( j ) ).startsWith( key ) ) | |||
| { | |||
| osEnv.removeElementAt( j ); | |||
| break; | |||
| } | |||
| } | |||
| osEnv.addElement( env[ i ] ); | |||
| } | |||
| String[] result = new String[ osEnv.size() ]; | |||
| osEnv.copyInto( result ); | |||
| return result; | |||
| } | |||
| /** | |||
| * A command launcher for a particular JVM/OS platform. This class is a | |||
| * general purpose command launcher which can only launch commands in the | |||
| * current working directory. | |||
| * | |||
| * @author RT | |||
| */ | |||
| private static class CommandLauncher | |||
| { | |||
| /** | |||
| * Launches the given command in a new process. | |||
| * | |||
| * @param project The project that the command is part of | |||
| * @param cmd The command to execute | |||
| * @param env The environment for the new process. If null, the | |||
| * environment of the current proccess is used. | |||
| * @return Description of the Returned Value | |||
| * @exception IOException Description of Exception | |||
| */ | |||
| public Process exec( Project project, String[] cmd, String[] env ) | |||
| throws IOException | |||
| { | |||
| if( project != null ) | |||
| { | |||
| project.log( "Execute:CommandLauncher: " + | |||
| Commandline.toString( cmd ), Project.MSG_DEBUG ); | |||
| } | |||
| return Runtime.getRuntime().exec( cmd, env ); | |||
| } | |||
| /** | |||
| * Launches the given command in a new process, in the given working | |||
| * directory. | |||
| * | |||
| * @param project The project that the command is part of | |||
| * @param cmd The command to execute | |||
| * @param env The environment for the new process. If null, the | |||
| * environment of the current proccess is used. | |||
| * @param workingDir The directory to start the command in. If null, the | |||
| * current directory is used | |||
| * @return Description of the Returned Value | |||
| * @exception IOException Description of Exception | |||
| */ | |||
| public Process exec( Project project, String[] cmd, String[] env, File workingDir ) | |||
| throws IOException | |||
| { | |||
| if( workingDir == null ) | |||
| { | |||
| return exec( project, cmd, env ); | |||
| } | |||
| throw new IOException( "Cannot execute a process in different directory under this JVM" ); | |||
| } | |||
| } | |||
| /** | |||
| * A command launcher that proxies another command launcher. Sub-classes | |||
| * override exec(args, env, workdir) | |||
| * | |||
| * @author RT | |||
| */ | |||
| private static class CommandLauncherProxy extends CommandLauncher | |||
| { | |||
| private CommandLauncher _launcher; | |||
| CommandLauncherProxy( CommandLauncher launcher ) | |||
| { | |||
| _launcher = launcher; | |||
| } | |||
| /** | |||
| * Launches the given command in a new process. Delegates this method to | |||
| * the proxied launcher | |||
| * | |||
| * @param project Description of Parameter | |||
| * @param cmd Description of Parameter | |||
| * @param env Description of Parameter | |||
| * @return Description of the Returned Value | |||
| * @exception IOException Description of Exception | |||
| */ | |||
| public Process exec( Project project, String[] cmd, String[] env ) | |||
| throws IOException | |||
| { | |||
| return _launcher.exec( project, cmd, env ); | |||
| } | |||
| } | |||
| /** | |||
| * A command launcher for JDK/JRE 1.1 under Windows. Fixes quoting problems | |||
| * in Runtime.exec(). Can only launch commands in the current working | |||
| * directory | |||
| * | |||
| * @author RT | |||
| */ | |||
| private static class Java11CommandLauncher extends CommandLauncher | |||
| { | |||
| /** | |||
| * Launches the given command in a new process. Needs to quote arguments | |||
| * | |||
| * @param project Description of Parameter | |||
| * @param cmd Description of Parameter | |||
| * @param env Description of Parameter | |||
| * @return Description of the Returned Value | |||
| * @exception IOException Description of Exception | |||
| */ | |||
| public Process exec( Project project, String[] cmd, String[] env ) | |||
| throws IOException | |||
| { | |||
| // Need to quote arguments with spaces, and to escape quote characters | |||
| String[] newcmd = new String[ cmd.length ]; | |||
| for( int i = 0; i < cmd.length; i++ ) | |||
| { | |||
| newcmd[ i ] = Commandline.quoteArgument( cmd[ i ] ); | |||
| } | |||
| if( project != null ) | |||
| { | |||
| project.log( "Execute:Java11CommandLauncher: " + | |||
| Commandline.toString( newcmd ), Project.MSG_DEBUG ); | |||
| } | |||
| return Runtime.getRuntime().exec( newcmd, env ); | |||
| } | |||
| } | |||
| /** | |||
| * A command launcher for JDK/JRE 1.3 (and higher). Uses the built-in | |||
| * Runtime.exec() command | |||
| * | |||
| * @author RT | |||
| */ | |||
| private static class Java13CommandLauncher extends CommandLauncher | |||
| { | |||
| private Method _execWithCWD; | |||
| public Java13CommandLauncher() | |||
| throws NoSuchMethodException | |||
| { | |||
| // Locate method Runtime.exec(String[] cmdarray, String[] envp, File dir) | |||
| _execWithCWD = Runtime.class.getMethod( "exec", new Class[]{String[].class, String[].class, File.class} ); | |||
| } | |||
| /** | |||
| * Launches the given command in a new process, in the given working | |||
| * directory | |||
| * | |||
| * @param project Description of Parameter | |||
| * @param cmd Description of Parameter | |||
| * @param env Description of Parameter | |||
| * @param workingDir Description of Parameter | |||
| * @return Description of the Returned Value | |||
| * @exception IOException Description of Exception | |||
| */ | |||
| public Process exec( Project project, String[] cmd, String[] env, File workingDir ) | |||
| throws IOException | |||
| { | |||
| try | |||
| { | |||
| if( project != null ) | |||
| { | |||
| project.log( "Execute:Java13CommandLauncher: " + | |||
| Commandline.toString( cmd ), Project.MSG_DEBUG ); | |||
| } | |||
| Object[] arguments = {cmd, env, workingDir}; | |||
| return (Process)_execWithCWD.invoke( Runtime.getRuntime(), arguments ); | |||
| } | |||
| catch( InvocationTargetException exc ) | |||
| { | |||
| Throwable realexc = exc.getTargetException(); | |||
| if( realexc instanceof ThreadDeath ) | |||
| { | |||
| throw (ThreadDeath)realexc; | |||
| } | |||
| else if( realexc instanceof IOException ) | |||
| { | |||
| throw (IOException)realexc; | |||
| } | |||
| else | |||
| { | |||
| throw new BuildException( "Unable to execute command", realexc ); | |||
| } | |||
| } | |||
| catch( Exception exc ) | |||
| { | |||
| // IllegalAccess, IllegalArgument, ClassCast | |||
| throw new BuildException( "Unable to execute command", exc ); | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * A command launcher for Mac that uses a dodgy mechanism to change working | |||
| * directory before launching commands. | |||
| * | |||
| * @author RT | |||
| */ | |||
| private static class MacCommandLauncher extends CommandLauncherProxy | |||
| { | |||
| MacCommandLauncher( CommandLauncher launcher ) | |||
| { | |||
| super( launcher ); | |||
| } | |||
| /** | |||
| * Launches the given command in a new process, in the given working | |||
| * directory | |||
| * | |||
| * @param project Description of Parameter | |||
| * @param cmd Description of Parameter | |||
| * @param env Description of Parameter | |||
| * @param workingDir Description of Parameter | |||
| * @return Description of the Returned Value | |||
| * @exception IOException Description of Exception | |||
| */ | |||
| public Process exec( Project project, String[] cmd, String[] env, File workingDir ) | |||
| throws IOException | |||
| { | |||
| if( workingDir == null ) | |||
| { | |||
| return exec( project, cmd, env ); | |||
| } | |||
| System.getProperties().put( "user.dir", workingDir.getAbsolutePath() ); | |||
| try | |||
| { | |||
| return exec( project, cmd, env ); | |||
| } | |||
| finally | |||
| { | |||
| System.getProperties().put( "user.dir", antWorkingDirectory ); | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * A command launcher that uses an auxiliary perl script to launch commands | |||
| * in directories other than the current working directory. | |||
| * | |||
| * @author RT | |||
| */ | |||
| private static class PerlScriptCommandLauncher extends CommandLauncherProxy | |||
| { | |||
| private String _script; | |||
| PerlScriptCommandLauncher( String script, CommandLauncher launcher ) | |||
| { | |||
| super( launcher ); | |||
| _script = script; | |||
| } | |||
| /** | |||
| * Launches the given command in a new process, in the given working | |||
| * directory | |||
| * | |||
| * @param project Description of Parameter | |||
| * @param cmd Description of Parameter | |||
| * @param env Description of Parameter | |||
| * @param workingDir Description of Parameter | |||
| * @return Description of the Returned Value | |||
| * @exception IOException Description of Exception | |||
| */ | |||
| public Process exec( Project project, String[] cmd, String[] env, File workingDir ) | |||
| throws IOException | |||
| { | |||
| if( project == null ) | |||
| { | |||
| if( workingDir == null ) | |||
| { | |||
| return exec( project, cmd, env ); | |||
| } | |||
| throw new IOException( "Cannot locate antRun script: No project provided" ); | |||
| } | |||
| // Locate the auxiliary script | |||
| String antHome = project.getProperty( "ant.home" ); | |||
| if( antHome == null ) | |||
| { | |||
| throw new IOException( "Cannot locate antRun script: Property 'ant.home' not found" ); | |||
| } | |||
| String antRun = project.resolveFile( antHome + File.separator + _script ).toString(); | |||
| // Build the command | |||
| File commandDir = workingDir; | |||
| if( workingDir == null && project != null ) | |||
| { | |||
| commandDir = project.getBaseDir(); | |||
| } | |||
| String[] newcmd = new String[ cmd.length + 3 ]; | |||
| newcmd[ 0 ] = "perl"; | |||
| newcmd[ 1 ] = antRun; | |||
| newcmd[ 2 ] = commandDir.getAbsolutePath(); | |||
| System.arraycopy( cmd, 0, newcmd, 3, cmd.length ); | |||
| return exec( project, newcmd, env ); | |||
| } | |||
| } | |||
| /** | |||
| * A command launcher that uses an auxiliary script to launch commands in | |||
| * directories other than the current working directory. | |||
| * | |||
| * @author RT | |||
| */ | |||
| private static class ScriptCommandLauncher extends CommandLauncherProxy | |||
| { | |||
| private String _script; | |||
| ScriptCommandLauncher( String script, CommandLauncher launcher ) | |||
| { | |||
| super( launcher ); | |||
| _script = script; | |||
| } | |||
| /** | |||
| * Launches the given command in a new process, in the given working | |||
| * directory | |||
| * | |||
| * @param project Description of Parameter | |||
| * @param cmd Description of Parameter | |||
| * @param env Description of Parameter | |||
| * @param workingDir Description of Parameter | |||
| * @return Description of the Returned Value | |||
| * @exception IOException Description of Exception | |||
| */ | |||
| public Process exec( Project project, String[] cmd, String[] env, File workingDir ) | |||
| throws IOException | |||
| { | |||
| if( project == null ) | |||
| { | |||
| if( workingDir == null ) | |||
| { | |||
| return exec( project, cmd, env ); | |||
| } | |||
| throw new IOException( "Cannot locate antRun script: No project provided" ); | |||
| } | |||
| // Locate the auxiliary script | |||
| String antHome = project.getProperty( "ant.home" ); | |||
| if( antHome == null ) | |||
| { | |||
| throw new IOException( "Cannot locate antRun script: Property 'ant.home' not found" ); | |||
| } | |||
| String antRun = project.resolveFile( antHome + File.separator + _script ).toString(); | |||
| // Build the command | |||
| File commandDir = workingDir; | |||
| if( workingDir == null && project != null ) | |||
| { | |||
| commandDir = project.getBaseDir(); | |||
| } | |||
| String[] newcmd = new String[ cmd.length + 2 ]; | |||
| newcmd[ 0 ] = antRun; | |||
| newcmd[ 1 ] = commandDir.getAbsolutePath(); | |||
| System.arraycopy( cmd, 0, newcmd, 2, cmd.length ); | |||
| return exec( project, newcmd, env ); | |||
| } | |||
| } | |||
| /** | |||
| * A command launcher for Windows 2000/NT that uses 'cmd.exe' when launching | |||
| * commands in directories other than the current working directory. | |||
| * | |||
| * @author RT | |||
| */ | |||
| private static class WinNTCommandLauncher extends CommandLauncherProxy | |||
| { | |||
| WinNTCommandLauncher( CommandLauncher launcher ) | |||
| { | |||
| super( launcher ); | |||
| } | |||
| /** | |||
| * Launches the given command in a new process, in the given working | |||
| * directory. | |||
| * | |||
| * @param project Description of Parameter | |||
| * @param cmd Description of Parameter | |||
| * @param env Description of Parameter | |||
| * @param workingDir Description of Parameter | |||
| * @return Description of the Returned Value | |||
| * @exception IOException Description of Exception | |||
| */ | |||
| public Process exec( Project project, String[] cmd, String[] env, File workingDir ) | |||
| throws IOException | |||
| { | |||
| File commandDir = workingDir; | |||
| if( workingDir == null ) | |||
| { | |||
| if( project != null ) | |||
| { | |||
| commandDir = project.getBaseDir(); | |||
| } | |||
| else | |||
| { | |||
| return exec( project, cmd, env ); | |||
| } | |||
| } | |||
| // Use cmd.exe to change to the specified directory before running | |||
| // the command | |||
| final int preCmdLength = 6; | |||
| String[] newcmd = new String[ cmd.length + preCmdLength ]; | |||
| newcmd[ 0 ] = "cmd"; | |||
| newcmd[ 1 ] = "/c"; | |||
| newcmd[ 2 ] = "cd"; | |||
| newcmd[ 3 ] = "/d"; | |||
| newcmd[ 4 ] = commandDir.getAbsolutePath(); | |||
| newcmd[ 5 ] = "&&"; | |||
| System.arraycopy( cmd, 0, newcmd, preCmdLength, cmd.length ); | |||
| return exec( project, newcmd, env ); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,122 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.PrintStream; | |||
| import java.lang.reflect.InvocationTargetException; | |||
| import java.lang.reflect.Method; | |||
| import org.apache.tools.ant.AntClassLoader; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.types.Commandline; | |||
| import org.apache.tools.ant.types.CommandlineJava; | |||
| import org.apache.tools.ant.types.Path; | |||
| /* | |||
| * @author thomas.haas@softwired-inc.com | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| */ | |||
| public class ExecuteJava | |||
| { | |||
| private Commandline javaCommand = null; | |||
| private Path classpath = null; | |||
| private CommandlineJava.SysProperties sysProperties = null; | |||
| public void setClasspath( Path p ) | |||
| { | |||
| classpath = p; | |||
| } | |||
| public void setJavaCommand( Commandline javaCommand ) | |||
| { | |||
| this.javaCommand = javaCommand; | |||
| } | |||
| /** | |||
| * All output (System.out as well as System.err) will be written to this | |||
| * Stream. | |||
| * | |||
| * @param out The new Output value | |||
| * @deprecated manage output at the task level | |||
| */ | |||
| public void setOutput( PrintStream out ) { } | |||
| public void setSystemProperties( CommandlineJava.SysProperties s ) | |||
| { | |||
| sysProperties = s; | |||
| } | |||
| public void execute( Project project ) | |||
| throws BuildException | |||
| { | |||
| final String classname = javaCommand.getExecutable(); | |||
| final Object[] argument = {javaCommand.getArguments()}; | |||
| AntClassLoader loader = null; | |||
| try | |||
| { | |||
| if( sysProperties != null ) | |||
| { | |||
| sysProperties.setSystem(); | |||
| } | |||
| final Class[] param = {Class.forName( "[Ljava.lang.String;" )}; | |||
| Class target = null; | |||
| if( classpath == null ) | |||
| { | |||
| target = Class.forName( classname ); | |||
| } | |||
| else | |||
| { | |||
| loader = new AntClassLoader( project.getCoreLoader(), project, classpath, false ); | |||
| loader.setIsolated( true ); | |||
| loader.setThreadContextLoader(); | |||
| target = loader.forceLoadClass( classname ); | |||
| AntClassLoader.initializeClass( target ); | |||
| } | |||
| final Method main = target.getMethod( "main", param ); | |||
| main.invoke( null, argument ); | |||
| } | |||
| catch( NullPointerException e ) | |||
| { | |||
| throw new BuildException( "Could not find main() method in " + classname ); | |||
| } | |||
| catch( ClassNotFoundException e ) | |||
| { | |||
| throw new BuildException( "Could not find " + classname + ". Make sure you have it in your classpath" ); | |||
| } | |||
| catch( InvocationTargetException e ) | |||
| { | |||
| Throwable t = e.getTargetException(); | |||
| if( !( t instanceof SecurityException ) ) | |||
| { | |||
| throw new BuildException( t ); | |||
| } | |||
| else | |||
| { | |||
| throw ( SecurityException )t; | |||
| } | |||
| } | |||
| catch( Exception e ) | |||
| { | |||
| throw new BuildException( e ); | |||
| } | |||
| finally | |||
| { | |||
| if( loader != null ) | |||
| { | |||
| loader.resetThreadContextLoader(); | |||
| loader.cleanup(); | |||
| } | |||
| if( sysProperties != null ) | |||
| { | |||
| sysProperties.restoreSystem(); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,473 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| import java.util.Hashtable; | |||
| 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.types.Commandline; | |||
| import org.apache.tools.ant.types.EnumeratedAttribute; | |||
| import org.apache.tools.ant.types.FileSet; | |||
| import org.apache.tools.ant.types.Mapper; | |||
| import org.apache.tools.ant.util.FileNameMapper; | |||
| import org.apache.tools.ant.util.SourceFileScanner; | |||
| /** | |||
| * Executes a given command, supplying a set of files as arguments. | |||
| * | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| * @author <a href="mailto:mariusz@rakiura.org">Mariusz Nowostawski</a> | |||
| */ | |||
| public class ExecuteOn extends ExecTask | |||
| { | |||
| protected Vector filesets = new Vector(); | |||
| private boolean relative = false; | |||
| private boolean parallel = false; | |||
| protected String type = "file"; | |||
| protected Commandline.Marker srcFilePos = null; | |||
| private boolean skipEmpty = false; | |||
| protected Commandline.Marker targetFilePos = null; | |||
| protected Mapper mapperElement = null; | |||
| protected FileNameMapper mapper = null; | |||
| protected File destDir = null; | |||
| /** | |||
| * Has <srcfile> been specified before <targetfile> | |||
| */ | |||
| protected boolean srcIsFirst = true; | |||
| /** | |||
| * Set the destination directory. | |||
| * | |||
| * @param destDir The new Dest value | |||
| */ | |||
| public void setDest( File destDir ) | |||
| { | |||
| this.destDir = destDir; | |||
| } | |||
| /** | |||
| * Shall the command work on all specified files in parallel? | |||
| * | |||
| * @param parallel The new Parallel value | |||
| */ | |||
| public void setParallel( boolean parallel ) | |||
| { | |||
| this.parallel = parallel; | |||
| } | |||
| /** | |||
| * Should filenames be returned as relative path names? | |||
| * | |||
| * @param relative The new Relative value | |||
| */ | |||
| public void setRelative( boolean relative ) | |||
| { | |||
| this.relative = relative; | |||
| } | |||
| /** | |||
| * Should empty filesets be ignored? | |||
| * | |||
| * @param skip The new SkipEmptyFilesets value | |||
| */ | |||
| public void setSkipEmptyFilesets( boolean skip ) | |||
| { | |||
| skipEmpty = skip; | |||
| } | |||
| /** | |||
| * Shall the command work only on files, directories or both? | |||
| * | |||
| * @param type The new Type value | |||
| */ | |||
| public void setType( FileDirBoth type ) | |||
| { | |||
| this.type = type.getValue(); | |||
| } | |||
| /** | |||
| * Adds a set of files (nested fileset attribute). | |||
| * | |||
| * @param set The feature to be added to the Fileset attribute | |||
| */ | |||
| public void addFileset( FileSet set ) | |||
| { | |||
| filesets.addElement( set ); | |||
| } | |||
| /** | |||
| * Defines the FileNameMapper to use (nested mapper element). | |||
| * | |||
| * @return Description of the Returned Value | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| public Mapper createMapper() | |||
| throws BuildException | |||
| { | |||
| if( mapperElement != null ) | |||
| { | |||
| throw new BuildException( "Cannot define more than one mapper", | |||
| location ); | |||
| } | |||
| mapperElement = new Mapper( project ); | |||
| return mapperElement; | |||
| } | |||
| /** | |||
| * Marker that indicates where the name of the source file should be put on | |||
| * the command line. | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public Commandline.Marker createSrcfile() | |||
| { | |||
| if( srcFilePos != null ) | |||
| { | |||
| throw new BuildException( taskType + " doesn\'t support multiple srcfile elements.", | |||
| location ); | |||
| } | |||
| srcFilePos = cmdl.createMarker(); | |||
| return srcFilePos; | |||
| } | |||
| /** | |||
| * Marker that indicates where the name of the target file should be put on | |||
| * the command line. | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public Commandline.Marker createTargetfile() | |||
| { | |||
| if( targetFilePos != null ) | |||
| { | |||
| throw new BuildException( taskType + " doesn\'t support multiple targetfile elements.", | |||
| location ); | |||
| } | |||
| targetFilePos = cmdl.createMarker(); | |||
| srcIsFirst = ( srcFilePos != null ); | |||
| return targetFilePos; | |||
| } | |||
| /** | |||
| * Construct the command line for parallel execution. | |||
| * | |||
| * @param srcFiles The filenames to add to the commandline | |||
| * @param baseDirs Description of Parameter | |||
| * @return The Commandline value | |||
| */ | |||
| protected String[] getCommandline( String[] srcFiles, File[] baseDirs ) | |||
| { | |||
| Vector targets = new Vector(); | |||
| if( targetFilePos != null ) | |||
| { | |||
| Hashtable addedFiles = new Hashtable(); | |||
| for( int i = 0; i < srcFiles.length; i++ ) | |||
| { | |||
| String[] subTargets = mapper.mapFileName( srcFiles[i] ); | |||
| if( subTargets != null ) | |||
| { | |||
| for( int j = 0; j < subTargets.length; j++ ) | |||
| { | |||
| String name = null; | |||
| if( !relative ) | |||
| { | |||
| name = | |||
| ( new File( destDir, subTargets[j] ) ).getAbsolutePath(); | |||
| } | |||
| else | |||
| { | |||
| name = subTargets[j]; | |||
| } | |||
| if( !addedFiles.contains( name ) ) | |||
| { | |||
| targets.addElement( name ); | |||
| addedFiles.put( name, name ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| String[] targetFiles = new String[targets.size()]; | |||
| targets.copyInto( targetFiles ); | |||
| String[] orig = cmdl.getCommandline(); | |||
| String[] result = new String[orig.length + srcFiles.length + targetFiles.length]; | |||
| int srcIndex = orig.length; | |||
| if( srcFilePos != null ) | |||
| { | |||
| srcIndex = srcFilePos.getPosition(); | |||
| } | |||
| if( targetFilePos != null ) | |||
| { | |||
| int targetIndex = targetFilePos.getPosition(); | |||
| if( srcIndex < targetIndex | |||
| || ( srcIndex == targetIndex && srcIsFirst ) ) | |||
| { | |||
| // 0 --> srcIndex | |||
| System.arraycopy( orig, 0, result, 0, srcIndex ); | |||
| // srcIndex --> targetIndex | |||
| System.arraycopy( orig, srcIndex, result, | |||
| srcIndex + srcFiles.length, | |||
| targetIndex - srcIndex ); | |||
| // targets are already absolute file names | |||
| System.arraycopy( targetFiles, 0, result, | |||
| targetIndex + srcFiles.length, | |||
| targetFiles.length ); | |||
| // targetIndex --> end | |||
| System.arraycopy( orig, targetIndex, result, | |||
| targetIndex + srcFiles.length + targetFiles.length, | |||
| orig.length - targetIndex ); | |||
| } | |||
| else | |||
| { | |||
| // 0 --> targetIndex | |||
| System.arraycopy( orig, 0, result, 0, targetIndex ); | |||
| // targets are already absolute file names | |||
| System.arraycopy( targetFiles, 0, result, | |||
| targetIndex, | |||
| targetFiles.length ); | |||
| // targetIndex --> srcIndex | |||
| System.arraycopy( orig, targetIndex, result, | |||
| targetIndex + targetFiles.length, | |||
| srcIndex - targetIndex ); | |||
| // srcIndex --> end | |||
| System.arraycopy( orig, srcIndex, result, | |||
| srcIndex + srcFiles.length + targetFiles.length, | |||
| orig.length - srcIndex ); | |||
| srcIndex += targetFiles.length; | |||
| } | |||
| } | |||
| else | |||
| {// no targetFilePos | |||
| // 0 --> srcIndex | |||
| System.arraycopy( orig, 0, result, 0, srcIndex ); | |||
| // srcIndex --> end | |||
| System.arraycopy( orig, srcIndex, result, | |||
| srcIndex + srcFiles.length, | |||
| orig.length - srcIndex ); | |||
| } | |||
| // fill in source file names | |||
| for( int i = 0; i < srcFiles.length; i++ ) | |||
| { | |||
| if( !relative ) | |||
| { | |||
| result[srcIndex + i] = | |||
| ( new File( baseDirs[i], srcFiles[i] ) ).getAbsolutePath(); | |||
| } | |||
| else | |||
| { | |||
| result[srcIndex + i] = srcFiles[i]; | |||
| } | |||
| } | |||
| return result; | |||
| } | |||
| /** | |||
| * Construct the command line for serial execution. | |||
| * | |||
| * @param srcFile The filename to add to the commandline | |||
| * @param baseDir filename is relative to this dir | |||
| * @return The Commandline value | |||
| */ | |||
| protected String[] getCommandline( String srcFile, File baseDir ) | |||
| { | |||
| return getCommandline( new String[]{srcFile}, new File[]{baseDir} ); | |||
| } | |||
| /** | |||
| * Return the list of Directories from this DirectoryScanner that should be | |||
| * included on the command line. | |||
| * | |||
| * @param baseDir Description of Parameter | |||
| * @param ds Description of Parameter | |||
| * @return The Dirs value | |||
| */ | |||
| protected String[] getDirs( File baseDir, DirectoryScanner ds ) | |||
| { | |||
| if( mapper != null ) | |||
| { | |||
| SourceFileScanner sfs = new SourceFileScanner( this ); | |||
| return sfs.restrict( ds.getIncludedDirectories(), baseDir, destDir, | |||
| mapper ); | |||
| } | |||
| else | |||
| { | |||
| return ds.getIncludedDirectories(); | |||
| } | |||
| } | |||
| /** | |||
| * Return the list of files from this DirectoryScanner that should be | |||
| * included on the command line. | |||
| * | |||
| * @param baseDir Description of Parameter | |||
| * @param ds Description of Parameter | |||
| * @return The Files value | |||
| */ | |||
| protected String[] getFiles( File baseDir, DirectoryScanner ds ) | |||
| { | |||
| if( mapper != null ) | |||
| { | |||
| SourceFileScanner sfs = new SourceFileScanner( this ); | |||
| return sfs.restrict( ds.getIncludedFiles(), baseDir, destDir, | |||
| mapper ); | |||
| } | |||
| else | |||
| { | |||
| return ds.getIncludedFiles(); | |||
| } | |||
| } | |||
| protected void checkConfiguration() | |||
| { | |||
| if( "execon".equals( taskName ) ) | |||
| { | |||
| log( "!! execon is deprecated. Use apply instead. !!" ); | |||
| } | |||
| super.checkConfiguration(); | |||
| if( filesets.size() == 0 ) | |||
| { | |||
| throw new BuildException( "no filesets specified", location ); | |||
| } | |||
| if( targetFilePos != null || mapperElement != null | |||
| || destDir != null ) | |||
| { | |||
| if( mapperElement == null ) | |||
| { | |||
| throw new BuildException( "no mapper specified", location ); | |||
| } | |||
| if( mapperElement == null ) | |||
| { | |||
| throw new BuildException( "no dest attribute specified", | |||
| location ); | |||
| } | |||
| mapper = mapperElement.getImplementation(); | |||
| } | |||
| } | |||
| protected void runExec( Execute exe ) | |||
| throws BuildException | |||
| { | |||
| try | |||
| { | |||
| Vector fileNames = new Vector(); | |||
| Vector baseDirs = new Vector(); | |||
| for( int i = 0; i < filesets.size(); i++ ) | |||
| { | |||
| FileSet fs = ( FileSet )filesets.elementAt( i ); | |||
| File base = fs.getDir( project ); | |||
| DirectoryScanner ds = fs.getDirectoryScanner( project ); | |||
| if( !"dir".equals( type ) ) | |||
| { | |||
| String[] s = getFiles( base, ds ); | |||
| for( int j = 0; j < s.length; j++ ) | |||
| { | |||
| fileNames.addElement( s[j] ); | |||
| baseDirs.addElement( base ); | |||
| } | |||
| } | |||
| if( !"file".equals( type ) ) | |||
| { | |||
| String[] s = getDirs( base, ds ); | |||
| ; | |||
| for( int j = 0; j < s.length; j++ ) | |||
| { | |||
| fileNames.addElement( s[j] ); | |||
| baseDirs.addElement( base ); | |||
| } | |||
| } | |||
| if( fileNames.size() == 0 && skipEmpty ) | |||
| { | |||
| log( "Skipping fileset for directory " | |||
| + base + ". It is empty.", Project.MSG_INFO ); | |||
| continue; | |||
| } | |||
| if( !parallel ) | |||
| { | |||
| String[] s = new String[fileNames.size()]; | |||
| fileNames.copyInto( s ); | |||
| for( int j = 0; j < s.length; j++ ) | |||
| { | |||
| String[] command = getCommandline( s[j], base ); | |||
| log( "Executing " + Commandline.toString( command ), | |||
| Project.MSG_VERBOSE ); | |||
| exe.setCommandline( command ); | |||
| runExecute( exe ); | |||
| } | |||
| fileNames.removeAllElements(); | |||
| baseDirs.removeAllElements(); | |||
| } | |||
| } | |||
| if( parallel && ( fileNames.size() > 0 || !skipEmpty ) ) | |||
| { | |||
| String[] s = new String[fileNames.size()]; | |||
| fileNames.copyInto( s ); | |||
| File[] b = new File[baseDirs.size()]; | |||
| baseDirs.copyInto( b ); | |||
| String[] command = getCommandline( s, b ); | |||
| log( "Executing " + Commandline.toString( command ), | |||
| Project.MSG_VERBOSE ); | |||
| exe.setCommandline( command ); | |||
| runExecute( exe ); | |||
| } | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| throw new BuildException( "Execute failed: " + e, e, location ); | |||
| } | |||
| finally | |||
| { | |||
| // close the output file if required | |||
| logFlush(); | |||
| } | |||
| } | |||
| /** | |||
| * Enumerated attribute with the values "file", "dir" and "both" for the | |||
| * type attribute. | |||
| * | |||
| * @author RT | |||
| */ | |||
| public static class FileDirBoth extends EnumeratedAttribute | |||
| { | |||
| public String[] getValues() | |||
| { | |||
| return new String[]{"file", "dir", "both"}; | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,62 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.io.OutputStream; | |||
| /** | |||
| * Used by <code>Execute</code> to handle input and output stream of | |||
| * subprocesses. | |||
| * | |||
| * @author thomas.haas@softwired-inc.com | |||
| */ | |||
| public interface ExecuteStreamHandler | |||
| { | |||
| /** | |||
| * Install a handler for the input stream of the subprocess. | |||
| * | |||
| * @param os output stream to write to the standard input stream of the | |||
| * subprocess | |||
| * @exception IOException Description of Exception | |||
| */ | |||
| void setProcessInputStream( OutputStream os ) | |||
| throws IOException; | |||
| /** | |||
| * Install a handler for the error stream of the subprocess. | |||
| * | |||
| * @param is input stream to read from the error stream from the subprocess | |||
| * @exception IOException Description of Exception | |||
| */ | |||
| void setProcessErrorStream( InputStream is ) | |||
| throws IOException; | |||
| /** | |||
| * Install a handler for the output stream of the subprocess. | |||
| * | |||
| * @param is input stream to read from the error stream from the subprocess | |||
| * @exception IOException Description of Exception | |||
| */ | |||
| void setProcessOutputStream( InputStream is ) | |||
| throws IOException; | |||
| /** | |||
| * Start handling of the streams. | |||
| * | |||
| * @exception IOException Description of Exception | |||
| */ | |||
| void start() | |||
| throws IOException; | |||
| /** | |||
| * Stop handling of the streams - will not be restarted. | |||
| */ | |||
| void stop(); | |||
| } | |||
| @@ -0,0 +1,209 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import org.apache.tools.ant.BuildException; | |||
| /** | |||
| * Destroys a process running for too long. For example: <pre> | |||
| * ExecuteWatchdog watchdog = new ExecuteWatchdog(30000); | |||
| * Execute exec = new Execute(myloghandler, watchdog); | |||
| * exec.setCommandLine(mycmdline); | |||
| * int exitvalue = exec.execute(); | |||
| * if (exitvalue != SUCCESS && watchdog.killedProcess()){ | |||
| * // it was killed on purpose by the watchdog | |||
| * } | |||
| * </pre> | |||
| * | |||
| * @author thomas.haas@softwired-inc.com | |||
| * @author <a href="mailto:sbailliez@imediation.com">Stephane Bailliez</a> | |||
| * @see Execute | |||
| */ | |||
| public class ExecuteWatchdog implements Runnable | |||
| { | |||
| /** | |||
| * say whether or not the watchog is currently monitoring a process | |||
| */ | |||
| private boolean watch = false; | |||
| /** | |||
| * exception that might be thrown during the process execution | |||
| */ | |||
| private Exception caught = null; | |||
| /** | |||
| * say whether or not the process was killed due to running overtime | |||
| */ | |||
| private boolean killedProcess = false; | |||
| /** | |||
| * the process to execute and watch for duration | |||
| */ | |||
| private Process process; | |||
| /** | |||
| * timeout duration. Once the process running time exceeds this it should be | |||
| * killed | |||
| */ | |||
| private int timeout; | |||
| /** | |||
| * Creates a new watchdog with a given timeout. | |||
| * | |||
| * @param timeout the timeout for the process in milliseconds. It must be | |||
| * greather than 0. | |||
| */ | |||
| public ExecuteWatchdog( int timeout ) | |||
| { | |||
| if( timeout < 1 ) | |||
| { | |||
| throw new IllegalArgumentException( "timeout lesser than 1." ); | |||
| } | |||
| this.timeout = timeout; | |||
| } | |||
| /** | |||
| * Indicates whether or not the watchdog is still monitoring the process. | |||
| * | |||
| * @return <tt>true</tt> if the process is still running, otherwise <tt> | |||
| * false</tt> . | |||
| */ | |||
| public boolean isWatching() | |||
| { | |||
| return watch; | |||
| } | |||
| /** | |||
| * This method will rethrow the exception that was possibly caught during | |||
| * the run of the process. It will only remains valid once the process has | |||
| * been terminated either by 'error', timeout or manual intervention. | |||
| * Information will be discarded once a new process is ran. | |||
| * | |||
| * @throws BuildException a wrapped exception over the one that was silently | |||
| * swallowed and stored during the process run. | |||
| */ | |||
| public void checkException() | |||
| throws BuildException | |||
| { | |||
| if( caught != null ) | |||
| { | |||
| throw new BuildException( "Exception in ExecuteWatchdog.run: " | |||
| + caught.getMessage(), caught ); | |||
| } | |||
| } | |||
| /** | |||
| * Indicates whether the last process run was killed on timeout or not. | |||
| * | |||
| * @return <tt>true</tt> if the process was killed otherwise <tt>false</tt> | |||
| * . | |||
| */ | |||
| public boolean killedProcess() | |||
| { | |||
| return killedProcess; | |||
| } | |||
| /** | |||
| * Watches the process and terminates it, if it runs for to long. | |||
| */ | |||
| public synchronized void run() | |||
| { | |||
| try | |||
| { | |||
| // This isn't a Task, don't have a Project object to log. | |||
| // project.log("ExecuteWatchdog: timeout = "+timeout+" msec", Project.MSG_VERBOSE); | |||
| final long until = System.currentTimeMillis() + timeout; | |||
| long now; | |||
| while( watch && until > ( now = System.currentTimeMillis() ) ) | |||
| { | |||
| try | |||
| { | |||
| wait( until - now ); | |||
| } | |||
| catch( InterruptedException e ) | |||
| {} | |||
| } | |||
| // if we are here, either someone stopped the watchdog, | |||
| // we are on timeout and the process must be killed, or | |||
| // we are on timeout and the process has already stopped. | |||
| try | |||
| { | |||
| // We must check if the process was not stopped | |||
| // before being here | |||
| process.exitValue(); | |||
| } | |||
| catch( IllegalThreadStateException e ) | |||
| { | |||
| // the process is not terminated, if this is really | |||
| // a timeout and not a manual stop then kill it. | |||
| if( watch ) | |||
| { | |||
| killedProcess = true; | |||
| process.destroy(); | |||
| } | |||
| } | |||
| } | |||
| catch( Exception e ) | |||
| { | |||
| caught = e; | |||
| } | |||
| finally | |||
| { | |||
| cleanUp(); | |||
| } | |||
| } | |||
| /** | |||
| * Watches the given process and terminates it, if it runs for too long. All | |||
| * information from the previous run are reset. | |||
| * | |||
| * @param process the process to monitor. It cannot be <tt>null</tt> | |||
| * @throws IllegalStateException thrown if a process is still being | |||
| * monitored. | |||
| */ | |||
| public synchronized void start( Process process ) | |||
| { | |||
| if( process == null ) | |||
| { | |||
| throw new NullPointerException( "process is null." ); | |||
| } | |||
| if( this.process != null ) | |||
| { | |||
| throw new IllegalStateException( "Already running." ); | |||
| } | |||
| this.caught = null; | |||
| this.killedProcess = false; | |||
| this.watch = true; | |||
| this.process = process; | |||
| final Thread thread = new Thread( this, "WATCHDOG" ); | |||
| thread.setDaemon( true ); | |||
| thread.start(); | |||
| } | |||
| /** | |||
| * Stops the watcher. It will notify all threads possibly waiting on this | |||
| * object. | |||
| */ | |||
| public synchronized void stop() | |||
| { | |||
| watch = false; | |||
| notifyAll(); | |||
| } | |||
| /** | |||
| * reset the monitor flag and the process. | |||
| */ | |||
| protected void cleanUp() | |||
| { | |||
| watch = false; | |||
| process = null; | |||
| } | |||
| } | |||
| @@ -0,0 +1,83 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.ProjectHelper; | |||
| import org.apache.tools.ant.Task; | |||
| /** | |||
| * Just exit the active build, giving an additional message if available. | |||
| * | |||
| * @author <a href="mailto:nico@seessle.de">Nico Seessle</a> | |||
| */ | |||
| public class Exit extends Task | |||
| { | |||
| private String ifCondition, unlessCondition; | |||
| private String message; | |||
| public void setIf( String c ) | |||
| { | |||
| ifCondition = c; | |||
| } | |||
| public void setMessage( String value ) | |||
| { | |||
| this.message = value; | |||
| } | |||
| public void setUnless( String c ) | |||
| { | |||
| unlessCondition = c; | |||
| } | |||
| /** | |||
| * Set a multiline message. | |||
| * | |||
| * @param msg The feature to be added to the Text attribute | |||
| */ | |||
| public void addText( String msg ) | |||
| { | |||
| message += project.replaceProperties( msg ); | |||
| } | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| if( testIfCondition() && testUnlessCondition() ) | |||
| { | |||
| if( message != null && message.length() > 0 ) | |||
| { | |||
| throw new BuildException( message ); | |||
| } | |||
| else | |||
| { | |||
| throw new BuildException( "No message" ); | |||
| } | |||
| } | |||
| } | |||
| private boolean testIfCondition() | |||
| { | |||
| if( ifCondition == null || "".equals( ifCondition ) ) | |||
| { | |||
| return true; | |||
| } | |||
| return project.getProperty( ifCondition ) != null; | |||
| } | |||
| private boolean testUnlessCondition() | |||
| { | |||
| if( unlessCondition == null || "".equals( unlessCondition ) ) | |||
| { | |||
| return true; | |||
| } | |||
| return project.getProperty( unlessCondition ) == null; | |||
| } | |||
| } | |||
| @@ -0,0 +1,303 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.File; | |||
| import java.io.FileInputStream; | |||
| import java.io.FileNotFoundException; | |||
| import java.io.FileOutputStream; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.util.Date; | |||
| import java.util.Vector; | |||
| import java.util.zip.ZipEntry; | |||
| import java.util.zip.ZipInputStream; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.DirectoryScanner; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.types.FileSet; | |||
| import org.apache.tools.ant.types.PatternSet; | |||
| import org.apache.tools.ant.util.FileUtils; | |||
| /** | |||
| * Unzip a file. | |||
| * | |||
| * @author costin@dnt.ro | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| * @author <a href="mailto:umagesh@rediffmail.com">Magesh Umasankar</a> | |||
| */ | |||
| public class Expand extends MatchingTask | |||
| {// req | |||
| private boolean overwrite = true; | |||
| private Vector patternsets = new Vector(); | |||
| private Vector filesets = new Vector(); | |||
| private File dest;//req | |||
| private File source; | |||
| /** | |||
| * Set the destination directory. File will be unzipped into the destination | |||
| * directory. | |||
| * | |||
| * @param d Path to the directory. | |||
| */ | |||
| public void setDest( File d ) | |||
| { | |||
| this.dest = d; | |||
| } | |||
| /** | |||
| * Should we overwrite files in dest, even if they are newer than the | |||
| * corresponding entries in the archive? | |||
| * | |||
| * @param b The new Overwrite value | |||
| */ | |||
| public void setOverwrite( boolean b ) | |||
| { | |||
| overwrite = b; | |||
| } | |||
| /** | |||
| * Set the path to zip-file. | |||
| * | |||
| * @param s Path to zip-file. | |||
| */ | |||
| public void setSrc( File s ) | |||
| { | |||
| this.source = s; | |||
| } | |||
| /** | |||
| * Add a fileset | |||
| * | |||
| * @param set The feature to be added to the Fileset attribute | |||
| */ | |||
| public void addFileset( FileSet set ) | |||
| { | |||
| filesets.addElement( set ); | |||
| } | |||
| /** | |||
| * Add a patternset | |||
| * | |||
| * @param set The feature to be added to the Patternset attribute | |||
| */ | |||
| public void addPatternset( PatternSet set ) | |||
| { | |||
| patternsets.addElement( set ); | |||
| } | |||
| /** | |||
| * Do the work. | |||
| * | |||
| * @exception BuildException Thrown in unrecoverable error. | |||
| */ | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| if( "expand".equals( taskType ) ) | |||
| { | |||
| log( "!! expand is deprecated. Use unzip instead. !!" ); | |||
| } | |||
| if( source == null && filesets.size() == 0 ) | |||
| { | |||
| throw new BuildException( "src attribute and/or filesets must be specified" ); | |||
| } | |||
| if( dest == null ) | |||
| { | |||
| throw new BuildException( | |||
| "Dest attribute must be specified" ); | |||
| } | |||
| if( dest.exists() && !dest.isDirectory() ) | |||
| { | |||
| throw new BuildException( "Dest must be a directory.", location ); | |||
| } | |||
| FileUtils fileUtils = FileUtils.newFileUtils(); | |||
| if( source != null ) | |||
| { | |||
| if( source.isDirectory() ) | |||
| { | |||
| throw new BuildException( "Src must not be a directory." + | |||
| " Use nested filesets instead.", location ); | |||
| } | |||
| else | |||
| { | |||
| expandFile( fileUtils, source, dest ); | |||
| } | |||
| } | |||
| if( filesets.size() > 0 ) | |||
| { | |||
| for( int j = 0; j < filesets.size(); j++ ) | |||
| { | |||
| FileSet fs = ( FileSet )filesets.elementAt( j ); | |||
| DirectoryScanner ds = fs.getDirectoryScanner( project ); | |||
| File fromDir = fs.getDir( project ); | |||
| String[] files = ds.getIncludedFiles(); | |||
| for( int i = 0; i < files.length; ++i ) | |||
| { | |||
| File file = new File( fromDir, files[i] ); | |||
| expandFile( fileUtils, file, dest ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| /* | |||
| * This method is to be overridden by extending unarchival tasks. | |||
| */ | |||
| protected void expandFile( FileUtils fileUtils, File srcF, File dir ) | |||
| { | |||
| ZipInputStream zis = null; | |||
| try | |||
| { | |||
| // code from WarExpand | |||
| zis = new ZipInputStream( new FileInputStream( srcF ) ); | |||
| ZipEntry ze = null; | |||
| while( ( ze = zis.getNextEntry() ) != null ) | |||
| { | |||
| extractFile( fileUtils, srcF, dir, zis, | |||
| ze.getName(), | |||
| new Date( ze.getTime() ), | |||
| ze.isDirectory() ); | |||
| } | |||
| log( "expand complete", Project.MSG_VERBOSE ); | |||
| } | |||
| catch( IOException ioe ) | |||
| { | |||
| throw new BuildException( "Error while expanding " + srcF.getPath(), ioe ); | |||
| } | |||
| finally | |||
| { | |||
| if( zis != null ) | |||
| { | |||
| try | |||
| { | |||
| zis.close(); | |||
| } | |||
| catch( IOException e ) | |||
| {} | |||
| } | |||
| } | |||
| } | |||
| protected void extractFile( FileUtils fileUtils, File srcF, File dir, | |||
| InputStream compressedInputStream, | |||
| String entryName, | |||
| Date entryDate, boolean isDirectory ) | |||
| throws IOException | |||
| { | |||
| if( patternsets != null && patternsets.size() > 0 ) | |||
| { | |||
| String name = entryName; | |||
| boolean included = false; | |||
| for( int v = 0; v < patternsets.size(); v++ ) | |||
| { | |||
| PatternSet p = ( PatternSet )patternsets.elementAt( v ); | |||
| String[] incls = p.getIncludePatterns( project ); | |||
| if( incls != null ) | |||
| { | |||
| for( int w = 0; w < incls.length; w++ ) | |||
| { | |||
| boolean isIncl = DirectoryScanner.match( incls[w], name ); | |||
| if( isIncl ) | |||
| { | |||
| included = true; | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| String[] excls = p.getExcludePatterns( project ); | |||
| if( excls != null ) | |||
| { | |||
| for( int w = 0; w < excls.length; w++ ) | |||
| { | |||
| boolean isExcl = DirectoryScanner.match( excls[w], name ); | |||
| if( isExcl ) | |||
| { | |||
| included = false; | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| if( !included ) | |||
| { | |||
| //Do not process this file | |||
| return; | |||
| } | |||
| } | |||
| File f = fileUtils.resolveFile( dir, entryName ); | |||
| try | |||
| { | |||
| if( !overwrite && f.exists() | |||
| && f.lastModified() >= entryDate.getTime() ) | |||
| { | |||
| log( "Skipping " + f + " as it is up-to-date", | |||
| Project.MSG_DEBUG ); | |||
| return; | |||
| } | |||
| log( "expanding " + entryName + " to " + f, | |||
| Project.MSG_VERBOSE ); | |||
| // create intermediary directories - sometimes zip don't add them | |||
| File dirF = fileUtils.getParentFile( f ); | |||
| dirF.mkdirs(); | |||
| if( isDirectory ) | |||
| { | |||
| f.mkdirs(); | |||
| } | |||
| else | |||
| { | |||
| byte[] buffer = new byte[1024]; | |||
| int length = 0; | |||
| FileOutputStream fos = null; | |||
| try | |||
| { | |||
| fos = new FileOutputStream( f ); | |||
| while( ( length = | |||
| compressedInputStream.read( buffer ) ) >= 0 ) | |||
| { | |||
| fos.write( buffer, 0, length ); | |||
| } | |||
| fos.close(); | |||
| fos = null; | |||
| } | |||
| finally | |||
| { | |||
| if( fos != null ) | |||
| { | |||
| try | |||
| { | |||
| fos.close(); | |||
| } | |||
| catch( IOException e ) | |||
| {} | |||
| } | |||
| } | |||
| } | |||
| fileUtils.setFileLastModified( f, entryDate.getTime() ); | |||
| } | |||
| catch( FileNotFoundException ex ) | |||
| { | |||
| log( "Unable to expand to file " + f.getPath(), Project.MSG_WARN ); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,74 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.File; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.Task; | |||
| /** | |||
| * This task sets a token filter that is used by the file copy methods of the | |||
| * project to do token substitution, or sets mutiple tokens by reading these | |||
| * from a file. | |||
| * | |||
| * @author Stefano Mazzocchi <a href="mailto:stefano@apache.org"> | |||
| * stefano@apache.org</a> | |||
| * @author Gero Vermaas <a href="mailto:gero@xs4all.nl">gero@xs4all.nl</a> | |||
| * @author <A href="gholam@xtra.co.nz">Michael McCallum</A> | |||
| */ | |||
| public class Filter extends Task | |||
| { | |||
| private File filtersFile; | |||
| private String token; | |||
| private String value; | |||
| public void setFiltersfile( File filtersFile ) | |||
| { | |||
| this.filtersFile = filtersFile; | |||
| } | |||
| public void setToken( String token ) | |||
| { | |||
| this.token = token; | |||
| } | |||
| public void setValue( String value ) | |||
| { | |||
| this.value = value; | |||
| } | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| boolean isFiltersFromFile = filtersFile != null && token == null && value == null; | |||
| boolean isSingleFilter = filtersFile == null && token != null && value != null; | |||
| if( !isFiltersFromFile && !isSingleFilter ) | |||
| { | |||
| throw new BuildException( "both token and value parameters, or only a filtersFile parameter is required", location ); | |||
| } | |||
| if( isSingleFilter ) | |||
| { | |||
| project.getGlobalFilterSet().addFilter( token, value ); | |||
| } | |||
| if( isFiltersFromFile ) | |||
| { | |||
| readFilters(); | |||
| } | |||
| } | |||
| protected void readFilters() | |||
| throws BuildException | |||
| { | |||
| log( "Reading filters from " + filtersFile, Project.MSG_VERBOSE ); | |||
| project.getGlobalFilterSet().readFiltersFromFile( filtersFile ); | |||
| } | |||
| } | |||
| @@ -0,0 +1,93 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.FileInputStream; | |||
| import java.io.FileOutputStream; | |||
| import java.io.IOException; | |||
| import java.util.zip.GZIPInputStream; | |||
| import org.apache.tools.ant.BuildException; | |||
| /** | |||
| * Expands a file that has been compressed with the GZIP algorithm. Normally | |||
| * used to compress non-compressed archives such as TAR files. | |||
| * | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| * @author <a href="mailto:umagesh@rediffmail.com">Magesh Umasankar</a> | |||
| */ | |||
| public class GUnzip extends Unpack | |||
| { | |||
| private final static String DEFAULT_EXTENSION = ".gz"; | |||
| protected String getDefaultExtension() | |||
| { | |||
| return DEFAULT_EXTENSION; | |||
| } | |||
| protected void extract() | |||
| { | |||
| if( source.lastModified() > dest.lastModified() ) | |||
| { | |||
| log( "Expanding " + source.getAbsolutePath() + " to " | |||
| + dest.getAbsolutePath() ); | |||
| FileOutputStream out = null; | |||
| GZIPInputStream zIn = null; | |||
| FileInputStream fis = null; | |||
| try | |||
| { | |||
| out = new FileOutputStream( dest ); | |||
| fis = new FileInputStream( source ); | |||
| zIn = new GZIPInputStream( fis ); | |||
| byte[] buffer = new byte[8 * 1024]; | |||
| int count = 0; | |||
| do | |||
| { | |||
| out.write( buffer, 0, count ); | |||
| count = zIn.read( buffer, 0, buffer.length ); | |||
| }while ( count != -1 ); | |||
| } | |||
| catch( IOException ioe ) | |||
| { | |||
| String msg = "Problem expanding gzip " + ioe.getMessage(); | |||
| throw new BuildException( msg, ioe, location ); | |||
| } | |||
| finally | |||
| { | |||
| if( fis != null ) | |||
| { | |||
| try | |||
| { | |||
| fis.close(); | |||
| } | |||
| catch( IOException ioex ) | |||
| {} | |||
| } | |||
| if( out != null ) | |||
| { | |||
| try | |||
| { | |||
| out.close(); | |||
| } | |||
| catch( IOException ioex ) | |||
| {} | |||
| } | |||
| if( zIn != null ) | |||
| { | |||
| try | |||
| { | |||
| zIn.close(); | |||
| } | |||
| catch( IOException ioex ) | |||
| {} | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,53 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.FileOutputStream; | |||
| import java.io.IOException; | |||
| import java.util.zip.GZIPOutputStream; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.taskdefs.Pack; | |||
| /** | |||
| * Compresses a file with the GZIP algorithm. Normally used to compress | |||
| * non-compressed archives such as TAR files. | |||
| * | |||
| * @author James Davidson <a href="mailto:duncan@x180.com">duncan@x180.com</a> | |||
| * @author Jon S. Stevens <a href="mailto:jon@clearink.com">jon@clearink.com</a> | |||
| * @author <a href="mailto:umagesh@rediffmail.com">Magesh Umasankar</a> | |||
| */ | |||
| public class GZip extends Pack | |||
| { | |||
| protected void pack() | |||
| { | |||
| GZIPOutputStream zOut = null; | |||
| try | |||
| { | |||
| zOut = new GZIPOutputStream( new FileOutputStream( zipFile ) ); | |||
| zipFile( source, zOut ); | |||
| } | |||
| catch( IOException ioe ) | |||
| { | |||
| String msg = "Problem creating gzip " + ioe.getMessage(); | |||
| throw new BuildException( msg, ioe, location ); | |||
| } | |||
| finally | |||
| { | |||
| if( zOut != null ) | |||
| { | |||
| try | |||
| { | |||
| // close up | |||
| zOut.close(); | |||
| } | |||
| catch( IOException e ) | |||
| {} | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,350 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.util.Enumeration; | |||
| import java.util.Vector; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.Task; | |||
| import org.apache.tools.ant.types.Commandline; | |||
| /** | |||
| * Generates a key. | |||
| * | |||
| * @author <a href="mailto:donaldp@apache.org">Peter Donald</a> | |||
| */ | |||
| public class GenerateKey extends Task | |||
| { | |||
| /** | |||
| * The alias of signer. | |||
| */ | |||
| protected String alias; | |||
| protected String dname; | |||
| protected DistinguishedName expandedDname; | |||
| protected String keyalg; | |||
| protected String keypass; | |||
| protected int keysize; | |||
| /** | |||
| * The name of keystore file. | |||
| */ | |||
| protected String keystore; | |||
| protected String sigalg; | |||
| protected String storepass; | |||
| protected String storetype; | |||
| protected int validity; | |||
| protected boolean verbose; | |||
| public void setAlias( final String alias ) | |||
| { | |||
| this.alias = alias; | |||
| } | |||
| public void setDname( final String dname ) | |||
| { | |||
| if( null != expandedDname ) | |||
| { | |||
| throw new BuildException( "It is not possible to specify dname both " + | |||
| "as attribute and element." ); | |||
| } | |||
| this.dname = dname; | |||
| } | |||
| public void setKeyalg( final String keyalg ) | |||
| { | |||
| this.keyalg = keyalg; | |||
| } | |||
| public void setKeypass( final String keypass ) | |||
| { | |||
| this.keypass = keypass; | |||
| } | |||
| public void setKeysize( final String keysize ) | |||
| throws BuildException | |||
| { | |||
| try | |||
| { | |||
| this.keysize = Integer.parseInt( keysize ); | |||
| } | |||
| catch( final NumberFormatException nfe ) | |||
| { | |||
| throw new BuildException( "KeySize attribute should be a integer" ); | |||
| } | |||
| } | |||
| public void setKeystore( final String keystore ) | |||
| { | |||
| this.keystore = keystore; | |||
| } | |||
| public void setSigalg( final String sigalg ) | |||
| { | |||
| this.sigalg = sigalg; | |||
| } | |||
| public void setStorepass( final String storepass ) | |||
| { | |||
| this.storepass = storepass; | |||
| } | |||
| public void setStoretype( final String storetype ) | |||
| { | |||
| this.storetype = storetype; | |||
| } | |||
| public void setValidity( final String validity ) | |||
| throws BuildException | |||
| { | |||
| try | |||
| { | |||
| this.validity = Integer.parseInt( validity ); | |||
| } | |||
| catch( final NumberFormatException nfe ) | |||
| { | |||
| throw new BuildException( "Validity attribute should be a integer" ); | |||
| } | |||
| } | |||
| public void setVerbose( final boolean verbose ) | |||
| { | |||
| this.verbose = verbose; | |||
| } | |||
| public DistinguishedName createDname() | |||
| throws BuildException | |||
| { | |||
| if( null != expandedDname ) | |||
| { | |||
| throw new BuildException( "DName sub-element can only be specified once." ); | |||
| } | |||
| if( null != dname ) | |||
| { | |||
| throw new BuildException( "It is not possible to specify dname both " + | |||
| "as attribute and element." ); | |||
| } | |||
| expandedDname = new DistinguishedName(); | |||
| return expandedDname; | |||
| } | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| if( project.getJavaVersion().equals( Project.JAVA_1_1 ) ) | |||
| { | |||
| throw new BuildException( "The genkey task is only available on JDK" + | |||
| " versions 1.2 or greater" ); | |||
| } | |||
| if( null == alias ) | |||
| { | |||
| throw new BuildException( "alias attribute must be set" ); | |||
| } | |||
| if( null == storepass ) | |||
| { | |||
| throw new BuildException( "storepass attribute must be set" ); | |||
| } | |||
| if( null == dname && null == expandedDname ) | |||
| { | |||
| throw new BuildException( "dname must be set" ); | |||
| } | |||
| final StringBuffer sb = new StringBuffer(); | |||
| sb.append( "keytool -genkey " ); | |||
| if( verbose ) | |||
| { | |||
| sb.append( "-v " ); | |||
| } | |||
| sb.append( "-alias \"" ); | |||
| sb.append( alias ); | |||
| sb.append( "\" " ); | |||
| if( null != dname ) | |||
| { | |||
| sb.append( "-dname \"" ); | |||
| sb.append( dname ); | |||
| sb.append( "\" " ); | |||
| } | |||
| if( null != expandedDname ) | |||
| { | |||
| sb.append( "-dname \"" ); | |||
| sb.append( expandedDname ); | |||
| sb.append( "\" " ); | |||
| } | |||
| if( null != keystore ) | |||
| { | |||
| sb.append( "-keystore \"" ); | |||
| sb.append( keystore ); | |||
| sb.append( "\" " ); | |||
| } | |||
| if( null != storepass ) | |||
| { | |||
| sb.append( "-storepass \"" ); | |||
| sb.append( storepass ); | |||
| sb.append( "\" " ); | |||
| } | |||
| if( null != storetype ) | |||
| { | |||
| sb.append( "-storetype \"" ); | |||
| sb.append( storetype ); | |||
| sb.append( "\" " ); | |||
| } | |||
| sb.append( "-keypass \"" ); | |||
| if( null != keypass ) | |||
| { | |||
| sb.append( keypass ); | |||
| } | |||
| else | |||
| { | |||
| sb.append( storepass ); | |||
| } | |||
| sb.append( "\" " ); | |||
| if( null != sigalg ) | |||
| { | |||
| sb.append( "-sigalg \"" ); | |||
| sb.append( sigalg ); | |||
| sb.append( "\" " ); | |||
| } | |||
| if( null != keyalg ) | |||
| { | |||
| sb.append( "-keyalg \"" ); | |||
| sb.append( keyalg ); | |||
| sb.append( "\" " ); | |||
| } | |||
| if( 0 < keysize ) | |||
| { | |||
| sb.append( "-keysize \"" ); | |||
| sb.append( keysize ); | |||
| sb.append( "\" " ); | |||
| } | |||
| if( 0 < validity ) | |||
| { | |||
| sb.append( "-validity \"" ); | |||
| sb.append( validity ); | |||
| sb.append( "\" " ); | |||
| } | |||
| log( "Generating Key for " + alias ); | |||
| final ExecTask cmd = ( ExecTask )project.createTask( "exec" ); | |||
| cmd.setCommand( new Commandline( sb.toString() ) ); | |||
| cmd.setFailonerror( true ); | |||
| cmd.setTaskName( getTaskName() ); | |||
| cmd.execute(); | |||
| } | |||
| public static class DistinguishedName | |||
| { | |||
| private Vector params = new Vector(); | |||
| private String name; | |||
| private String path; | |||
| public Enumeration getParams() | |||
| { | |||
| return params.elements(); | |||
| } | |||
| public Object createParam() | |||
| { | |||
| DnameParam param = new DnameParam(); | |||
| params.addElement( param ); | |||
| return param; | |||
| } | |||
| public String encode( final String string ) | |||
| { | |||
| int end = string.indexOf( ',' ); | |||
| if( -1 == end ) | |||
| return string; | |||
| final StringBuffer sb = new StringBuffer(); | |||
| int start = 0; | |||
| while( -1 != end ) | |||
| { | |||
| sb.append( string.substring( start, end ) ); | |||
| sb.append( "\\," ); | |||
| start = end + 1; | |||
| end = string.indexOf( ',', start ); | |||
| } | |||
| sb.append( string.substring( start ) ); | |||
| return sb.toString(); | |||
| } | |||
| public String toString() | |||
| { | |||
| final int size = params.size(); | |||
| final StringBuffer sb = new StringBuffer(); | |||
| boolean firstPass = true; | |||
| for( int i = 0; i < size; i++ ) | |||
| { | |||
| if( !firstPass ) | |||
| { | |||
| sb.append( " ," ); | |||
| } | |||
| firstPass = false; | |||
| final DnameParam param = ( DnameParam )params.elementAt( i ); | |||
| sb.append( encode( param.getName() ) ); | |||
| sb.append( '=' ); | |||
| sb.append( encode( param.getValue() ) ); | |||
| } | |||
| return sb.toString(); | |||
| } | |||
| } | |||
| public static class DnameParam | |||
| { | |||
| private String name; | |||
| private String value; | |||
| public void setName( String name ) | |||
| { | |||
| this.name = name; | |||
| } | |||
| public void setValue( String value ) | |||
| { | |||
| this.value = value; | |||
| } | |||
| public String getName() | |||
| { | |||
| return name; | |||
| } | |||
| public String getValue() | |||
| { | |||
| return value; | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,410 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.File; | |||
| import java.io.FileOutputStream; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.net.HttpURLConnection; | |||
| import java.net.URL; | |||
| import java.net.URLConnection; | |||
| import java.util.Date; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.Task; | |||
| /** | |||
| * Get a particular file from a URL source. Options include verbose reporting, | |||
| * timestamp based fetches and controlling actions on failures. NB: access | |||
| * through a firewall only works if the whole Java runtime is correctly | |||
| * configured. | |||
| * | |||
| * @author costin@dnt.ro | |||
| * @author gg@grtmail.com (Added Java 1.1 style HTTP basic auth) | |||
| */ | |||
| public class Get extends Task | |||
| {// required | |||
| private boolean verbose = false; | |||
| private boolean useTimestamp = false;//off by default | |||
| private boolean ignoreErrors = false; | |||
| private String uname = null; | |||
| private String pword = null;// required | |||
| private File dest; | |||
| private URL source; | |||
| /** | |||
| * Where to copy the source file. | |||
| * | |||
| * @param dest Path to file. | |||
| */ | |||
| public void setDest( File dest ) | |||
| { | |||
| this.dest = dest; | |||
| } | |||
| /** | |||
| * Don't stop if get fails if set to "<CODE>true</CODE>". | |||
| * | |||
| * @param v if "true" then don't report download errors up to ant | |||
| */ | |||
| public void setIgnoreErrors( boolean v ) | |||
| { | |||
| ignoreErrors = v; | |||
| } | |||
| /** | |||
| * password for the basic auth. | |||
| * | |||
| * @param p password for authentication | |||
| */ | |||
| public void setPassword( String p ) | |||
| { | |||
| this.pword = p; | |||
| } | |||
| /** | |||
| * Set the URL. | |||
| * | |||
| * @param u URL for the file. | |||
| */ | |||
| public void setSrc( URL u ) | |||
| { | |||
| this.source = u; | |||
| } | |||
| /** | |||
| * Use timestamps, if set to "<CODE>true</CODE>". <p> | |||
| * | |||
| * In this situation, the if-modified-since header is set so that the file | |||
| * is only fetched if it is newer than the local file (or there is no local | |||
| * file) This flag is only valid on HTTP connections, it is ignored in other | |||
| * cases. When the flag is set, the local copy of the downloaded file will | |||
| * also have its timestamp set to the remote file time. <br> | |||
| * Note that remote files of date 1/1/1970 (GMT) are treated as 'no | |||
| * timestamp', and web servers often serve files with a timestamp in the | |||
| * future by replacing their timestamp with that of the current time. Also, | |||
| * inter-computer clock differences can cause no end of grief. | |||
| * | |||
| * @param v "true" to enable file time fetching | |||
| */ | |||
| public void setUseTimestamp( boolean v ) | |||
| { | |||
| if( project.getJavaVersion() != Project.JAVA_1_1 ) | |||
| { | |||
| useTimestamp = v; | |||
| } | |||
| } | |||
| /** | |||
| * Username for basic auth. | |||
| * | |||
| * @param u username for authentication | |||
| */ | |||
| public void setUsername( String u ) | |||
| { | |||
| this.uname = u; | |||
| } | |||
| /** | |||
| * Be verbose, if set to "<CODE>true</CODE>". | |||
| * | |||
| * @param v if "true" then be verbose | |||
| */ | |||
| public void setVerbose( boolean v ) | |||
| { | |||
| verbose = v; | |||
| } | |||
| /** | |||
| * Does the work. | |||
| * | |||
| * @exception BuildException Thrown in unrecoverable error. | |||
| */ | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| if( source == null ) | |||
| { | |||
| throw new BuildException( "src attribute is required", location ); | |||
| } | |||
| if( dest == null ) | |||
| { | |||
| throw new BuildException( "dest attribute is required", location ); | |||
| } | |||
| if( dest.exists() && dest.isDirectory() ) | |||
| { | |||
| throw new BuildException( "The specified destination is a directory", | |||
| location ); | |||
| } | |||
| if( dest.exists() && !dest.canWrite() ) | |||
| { | |||
| throw new BuildException( "Can't write to " + dest.getAbsolutePath(), | |||
| location ); | |||
| } | |||
| try | |||
| { | |||
| log( "Getting: " + source ); | |||
| //set the timestamp to the file date. | |||
| long timestamp = 0; | |||
| boolean hasTimestamp = false; | |||
| if( useTimestamp && dest.exists() ) | |||
| { | |||
| timestamp = dest.lastModified(); | |||
| if( verbose ) | |||
| { | |||
| Date t = new Date( timestamp ); | |||
| log( "local file date : " + t.toString() ); | |||
| } | |||
| hasTimestamp = true; | |||
| } | |||
| //set up the URL connection | |||
| URLConnection connection = source.openConnection(); | |||
| //modify the headers | |||
| //NB: things like user authentication could go in here too. | |||
| if( useTimestamp && hasTimestamp ) | |||
| { | |||
| connection.setIfModifiedSince( timestamp ); | |||
| } | |||
| // prepare Java 1.1 style credentials | |||
| if( uname != null || pword != null ) | |||
| { | |||
| String up = uname + ":" + pword; | |||
| String encoding; | |||
| // check to see if sun's Base64 encoder is available. | |||
| try | |||
| { | |||
| sun.misc.BASE64Encoder encoder = | |||
| ( sun.misc.BASE64Encoder )Class.forName( "sun.misc.BASE64Encoder" ).newInstance(); | |||
| encoding = encoder.encode( up.getBytes() ); | |||
| } | |||
| catch( Exception ex ) | |||
| {// sun's base64 encoder isn't available | |||
| Base64Converter encoder = new Base64Converter(); | |||
| encoding = encoder.encode( up.getBytes() ); | |||
| } | |||
| connection.setRequestProperty( "Authorization", "Basic " + encoding ); | |||
| } | |||
| //connect to the remote site (may take some time) | |||
| connection.connect(); | |||
| //next test for a 304 result (HTTP only) | |||
| if( connection instanceof HttpURLConnection ) | |||
| { | |||
| HttpURLConnection httpConnection = ( HttpURLConnection )connection; | |||
| if( httpConnection.getResponseCode() == HttpURLConnection.HTTP_NOT_MODIFIED ) | |||
| { | |||
| //not modified so no file download. just return instead | |||
| //and trace out something so the user doesn't think that the | |||
| //download happened when it didnt | |||
| log( "Not modified - so not downloaded" ); | |||
| return; | |||
| } | |||
| // test for 401 result (HTTP only) | |||
| if( httpConnection.getResponseCode() == HttpURLConnection.HTTP_UNAUTHORIZED ) | |||
| { | |||
| log( "Not authorized - check " + dest + " for details" ); | |||
| return; | |||
| } | |||
| } | |||
| //REVISIT: at this point even non HTTP connections may support the if-modified-since | |||
| //behaviour -we just check the date of the content and skip the write if it is not | |||
| //newer. Some protocols (FTP) dont include dates, of course. | |||
| FileOutputStream fos = new FileOutputStream( dest ); | |||
| InputStream is = null; | |||
| for( int i = 0; i < 3; i++ ) | |||
| { | |||
| try | |||
| { | |||
| is = connection.getInputStream(); | |||
| break; | |||
| } | |||
| catch( IOException ex ) | |||
| { | |||
| log( "Error opening connection " + ex ); | |||
| } | |||
| } | |||
| if( is == null ) | |||
| { | |||
| log( "Can't get " + source + " to " + dest ); | |||
| if( ignoreErrors ) | |||
| return; | |||
| throw new BuildException( "Can't get " + source + " to " + dest, | |||
| location ); | |||
| } | |||
| byte[] buffer = new byte[100 * 1024]; | |||
| int length; | |||
| while( ( length = is.read( buffer ) ) >= 0 ) | |||
| { | |||
| fos.write( buffer, 0, length ); | |||
| if( verbose ) | |||
| System.out.print( "." ); | |||
| } | |||
| if( verbose ) | |||
| System.out.println(); | |||
| fos.close(); | |||
| is.close(); | |||
| //if (and only if) the use file time option is set, then the | |||
| //saved file now has its timestamp set to that of the downloaded file | |||
| if( useTimestamp ) | |||
| { | |||
| long remoteTimestamp = connection.getLastModified(); | |||
| if( verbose ) | |||
| { | |||
| Date t = new Date( remoteTimestamp ); | |||
| log( "last modified = " + t.toString() | |||
| + ( ( remoteTimestamp == 0 ) ? " - using current time instead" : "" ) ); | |||
| } | |||
| if( remoteTimestamp != 0 ) | |||
| touchFile( dest, remoteTimestamp ); | |||
| } | |||
| } | |||
| catch( IOException ioe ) | |||
| { | |||
| log( "Error getting " + source + " to " + dest ); | |||
| if( ignoreErrors ) | |||
| return; | |||
| throw new BuildException( ioe); | |||
| } | |||
| } | |||
| /** | |||
| * set the timestamp of a named file to a specified time. | |||
| * | |||
| * @param file Description of Parameter | |||
| * @param timemillis Description of Parameter | |||
| * @return true if it succeeded. False means that this is a java1.1 system | |||
| * and that file times can not be set | |||
| * @exception BuildException Thrown in unrecoverable error. Likely this | |||
| * comes from file access failures. | |||
| */ | |||
| protected boolean touchFile( File file, long timemillis ) | |||
| throws BuildException | |||
| { | |||
| if( project.getJavaVersion() != Project.JAVA_1_1 ) | |||
| { | |||
| Touch touch = ( Touch )project.createTask( "touch" ); | |||
| touch.setOwningTarget( target ); | |||
| touch.setTaskName( getTaskName() ); | |||
| touch.setLocation( getLocation() ); | |||
| touch.setFile( file ); | |||
| touch.setMillis( timemillis ); | |||
| touch.touch(); | |||
| return true; | |||
| } | |||
| else | |||
| { | |||
| return false; | |||
| } | |||
| } | |||
| /** | |||
| * BASE 64 encoding of a String or an array of bytes. Based on RFC 1421. | |||
| * | |||
| * @author Unknown | |||
| * @author <a HREF="gg@grtmail.com">Gautam Guliani</a> | |||
| */ | |||
| class Base64Converter | |||
| { | |||
| public final char[] alphabet = { | |||
| 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 0 to 7 | |||
| 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 8 to 15 | |||
| 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 16 to 23 | |||
| 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', // 24 to 31 | |||
| 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', // 32 to 39 | |||
| 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', // 40 to 47 | |||
| 'w', 'x', 'y', 'z', '0', '1', '2', '3', // 48 to 55 | |||
| '4', '5', '6', '7', '8', '9', '+', '/'};// 56 to 63 | |||
| public String encode( String s ) | |||
| { | |||
| return encode( s.getBytes() ); | |||
| } | |||
| public String encode( byte[] octetString ) | |||
| { | |||
| int bits24; | |||
| int bits6; | |||
| char[] out | |||
| = new char[( ( octetString.length - 1 ) / 3 + 1 ) * 4]; | |||
| int outIndex = 0; | |||
| int i = 0; | |||
| while( ( i + 3 ) <= octetString.length ) | |||
| { | |||
| // store the octets | |||
| bits24 = ( octetString[i++] & 0xFF ) << 16; | |||
| bits24 |= ( octetString[i++] & 0xFF ) << 8; | |||
| bits6 = ( bits24 & 0x00FC0000 ) >> 18; | |||
| out[outIndex++] = alphabet[bits6]; | |||
| bits6 = ( bits24 & 0x0003F000 ) >> 12; | |||
| out[outIndex++] = alphabet[bits6]; | |||
| bits6 = ( bits24 & 0x00000FC0 ) >> 6; | |||
| out[outIndex++] = alphabet[bits6]; | |||
| bits6 = ( bits24 & 0x0000003F ); | |||
| out[outIndex++] = alphabet[bits6]; | |||
| } | |||
| if( octetString.length - i == 2 ) | |||
| { | |||
| // store the octets | |||
| bits24 = ( octetString[i] & 0xFF ) << 16; | |||
| bits24 |= ( octetString[i + 1] & 0xFF ) << 8; | |||
| bits6 = ( bits24 & 0x00FC0000 ) >> 18; | |||
| out[outIndex++] = alphabet[bits6]; | |||
| bits6 = ( bits24 & 0x0003F000 ) >> 12; | |||
| out[outIndex++] = alphabet[bits6]; | |||
| bits6 = ( bits24 & 0x00000FC0 ) >> 6; | |||
| out[outIndex++] = alphabet[bits6]; | |||
| // padding | |||
| out[outIndex++] = '='; | |||
| } | |||
| else if( octetString.length - i == 1 ) | |||
| { | |||
| // store the octets | |||
| bits24 = ( octetString[i] & 0xFF ) << 16; | |||
| bits6 = ( bits24 & 0x00FC0000 ) >> 18; | |||
| out[outIndex++] = alphabet[bits6]; | |||
| bits6 = ( bits24 & 0x0003F000 ) >> 12; | |||
| out[outIndex++] = alphabet[bits6]; | |||
| // padding | |||
| out[outIndex++] = '='; | |||
| out[outIndex++] = '='; | |||
| } | |||
| return new String( out ); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,153 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.BufferedReader; | |||
| import java.io.IOException; | |||
| import java.io.InputStreamReader; | |||
| import java.util.StringTokenizer; | |||
| import java.util.Vector; | |||
| import org.apache.tools.ant.*; | |||
| /** | |||
| * Ant task to read input line from console. | |||
| * | |||
| * @author Ulrich Schmidt <usch@usch.net> | |||
| */ | |||
| public class Input extends Task | |||
| { | |||
| private String validargs = null; | |||
| private String message = ""; | |||
| private String addproperty = null; | |||
| private String input = null; | |||
| /** | |||
| * No arg constructor. | |||
| */ | |||
| public Input() { } | |||
| /** | |||
| * Defines the name of a property to be created from input. Behaviour is | |||
| * according to property task which means that existing properties cannot be | |||
| * overriden. | |||
| * | |||
| * @param addproperty Name for the property to be created from input | |||
| */ | |||
| public void setAddproperty( String addproperty ) | |||
| { | |||
| this.addproperty = addproperty; | |||
| } | |||
| /** | |||
| * Sets the Message which gets displayed to the user during the build run. | |||
| * | |||
| * @param message The message to be displayed. | |||
| */ | |||
| public void setMessage( String message ) | |||
| { | |||
| this.message = message; | |||
| } | |||
| /** | |||
| * Sets surrogate input to allow automated testing. | |||
| * | |||
| * @param testinput The new Testinput value | |||
| */ | |||
| public void setTestinput( String testinput ) | |||
| { | |||
| this.input = testinput; | |||
| } | |||
| /** | |||
| * Defines valid input parameters as comma separated String. If set, input | |||
| * task will reject any input not defined as accepted and requires the user | |||
| * to reenter it. Validargs are case sensitive. If you want 'a' and 'A' to | |||
| * be accepted you need to define both values as accepted arguments. | |||
| * | |||
| * @param validargs A comma separated String defining valid input args. | |||
| */ | |||
| public void setValidargs( String validargs ) | |||
| { | |||
| this.validargs = validargs; | |||
| } | |||
| // copied n' pasted from org.apache.tools.ant.taskdefs.Exit | |||
| /** | |||
| * Set a multiline message. | |||
| * | |||
| * @param msg The feature to be added to the Text attribute | |||
| */ | |||
| public void addText( String msg ) | |||
| { | |||
| message += project.replaceProperties( msg ); | |||
| } | |||
| /** | |||
| * Actual test method executed by jakarta-ant. | |||
| * | |||
| * @exception BuildException | |||
| */ | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| Vector accept = null; | |||
| if( validargs != null ) | |||
| { | |||
| accept = new Vector(); | |||
| StringTokenizer stok = new StringTokenizer( validargs, ",", false ); | |||
| while( stok.hasMoreTokens() ) | |||
| { | |||
| accept.addElement( stok.nextToken() ); | |||
| } | |||
| } | |||
| log( message, Project.MSG_WARN ); | |||
| if( input == null ) | |||
| { | |||
| try | |||
| { | |||
| BufferedReader in = new BufferedReader( new InputStreamReader( System.in ) ); | |||
| input = in.readLine(); | |||
| if( accept != null ) | |||
| { | |||
| while( !accept.contains( input ) ) | |||
| { | |||
| log( message, Project.MSG_WARN ); | |||
| input = in.readLine(); | |||
| } | |||
| } | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| throw new BuildException( "Failed to read input from Console.", e ); | |||
| } | |||
| } | |||
| // not quite the original intention of this task but for the sake | |||
| // of testing ;-) | |||
| else | |||
| { | |||
| if( accept != null && ( !accept.contains( input ) ) ) | |||
| { | |||
| throw new BuildException( "Invalid input please reenter." ); | |||
| } | |||
| } | |||
| // adopted from org.apache.tools.ant.taskdefs.Property | |||
| if( addproperty != null ) | |||
| { | |||
| if( project.getProperty( addproperty ) == null ) | |||
| { | |||
| project.setProperty( addproperty, input ); | |||
| } | |||
| else | |||
| { | |||
| log( "Override ignored for " + addproperty, Project.MSG_VERBOSE ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,397 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.*; | |||
| import java.util.Enumeration; | |||
| import java.util.Vector; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.FileScanner; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.types.ZipFileSet; | |||
| import org.apache.tools.zip.ZipOutputStream; | |||
| /** | |||
| * Creates a JAR archive. | |||
| * | |||
| * @author James Davidson <a href="mailto:duncan@x180.com">duncan@x180.com</a> | |||
| */ | |||
| public class Jar extends Zip | |||
| { | |||
| /** | |||
| * The index file name. | |||
| */ | |||
| private final static String INDEX_NAME = "META-INF/INDEX.LIST"; | |||
| /** | |||
| * true if a manifest has been specified in the task | |||
| */ | |||
| private boolean buildFileManifest = false; | |||
| /** | |||
| * jar index is JDK 1.3+ only | |||
| */ | |||
| private boolean index = false; | |||
| private Manifest execManifest; | |||
| private Manifest manifest; | |||
| private File manifestFile; | |||
| /** | |||
| * constructor | |||
| */ | |||
| public Jar() | |||
| { | |||
| super(); | |||
| archiveType = "jar"; | |||
| emptyBehavior = "create"; | |||
| setEncoding( "UTF8" ); | |||
| } | |||
| /** | |||
| * Set whether or not to create an index list for classes to speed up | |||
| * classloading. | |||
| * | |||
| * @param flag The new Index value | |||
| */ | |||
| public void setIndex( boolean flag ) | |||
| { | |||
| index = flag; | |||
| } | |||
| /** | |||
| * @param jarFile The new Jarfile value | |||
| * @deprecated use setFile(File) instead. | |||
| */ | |||
| public void setJarfile( File jarFile ) | |||
| { | |||
| log( "DEPRECATED - The jarfile attribute is deprecated. Use file attribute instead." ); | |||
| setFile( jarFile ); | |||
| } | |||
| public void setManifest( File manifestFile ) | |||
| { | |||
| if( !manifestFile.exists() ) | |||
| { | |||
| throw new BuildException( "Manifest file: " + manifestFile + " does not exist.", | |||
| getLocation() ); | |||
| } | |||
| this.manifestFile = manifestFile; | |||
| Reader r = null; | |||
| try | |||
| { | |||
| r = new FileReader( manifestFile ); | |||
| Manifest newManifest = new Manifest( r ); | |||
| if( manifest == null ) | |||
| { | |||
| manifest = Manifest.getDefaultManifest(); | |||
| } | |||
| manifest.merge( newManifest ); | |||
| } | |||
| catch( ManifestException e ) | |||
| { | |||
| log( "Manifest is invalid: " + e.getMessage(), Project.MSG_ERR ); | |||
| throw new BuildException( "Invalid Manifest: " + manifestFile, e, getLocation() ); | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| throw new BuildException( "Unable to read manifest file: " + manifestFile, e ); | |||
| } | |||
| finally | |||
| { | |||
| if( r != null ) | |||
| { | |||
| try | |||
| { | |||
| r.close(); | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| // do nothing | |||
| } | |||
| } | |||
| } | |||
| } | |||
| public void setWhenempty( WhenEmpty we ) | |||
| { | |||
| log( "JARs are never empty, they contain at least a manifest file", | |||
| Project.MSG_WARN ); | |||
| } | |||
| public void addConfiguredManifest( Manifest newManifest ) | |||
| throws ManifestException | |||
| { | |||
| if( manifest == null ) | |||
| { | |||
| manifest = Manifest.getDefaultManifest(); | |||
| } | |||
| manifest.merge( newManifest ); | |||
| buildFileManifest = true; | |||
| } | |||
| public void addMetainf( ZipFileSet fs ) | |||
| { | |||
| // We just set the prefix for this fileset, and pass it up. | |||
| fs.setPrefix( "META-INF/" ); | |||
| super.addFileset( fs ); | |||
| } | |||
| /** | |||
| * Check whether the archive is up-to-date; | |||
| * | |||
| * @param scanners list of prepared scanners containing files to archive | |||
| * @param zipFile intended archive file (may or may not exist) | |||
| * @return true if nothing need be done (may have done something already); | |||
| * false if archive creation should proceed | |||
| * @exception BuildException if it likes | |||
| */ | |||
| protected boolean isUpToDate( FileScanner[] scanners, File zipFile ) | |||
| throws BuildException | |||
| { | |||
| // need to handle manifest as a special check | |||
| if( buildFileManifest || manifestFile == null ) | |||
| { | |||
| java.util.zip.ZipFile theZipFile = null; | |||
| try | |||
| { | |||
| theZipFile = new java.util.zip.ZipFile( zipFile ); | |||
| java.util.zip.ZipEntry entry = theZipFile.getEntry( "META-INF/MANIFEST.MF" ); | |||
| if( entry == null ) | |||
| { | |||
| log( "Updating jar since the current jar has no manifest", Project.MSG_VERBOSE ); | |||
| return false; | |||
| } | |||
| Manifest currentManifest = new Manifest( new InputStreamReader( theZipFile.getInputStream( entry ) ) ); | |||
| if( manifest == null ) | |||
| { | |||
| manifest = Manifest.getDefaultManifest(); | |||
| } | |||
| if( !currentManifest.equals( manifest ) ) | |||
| { | |||
| log( "Updating jar since jar manifest has changed", Project.MSG_VERBOSE ); | |||
| return false; | |||
| } | |||
| } | |||
| catch( Exception e ) | |||
| { | |||
| // any problems and we will rebuild | |||
| log( "Updating jar since cannot read current jar manifest: " + e.getClass().getName() + e.getMessage(), | |||
| Project.MSG_VERBOSE ); | |||
| return false; | |||
| } | |||
| finally | |||
| { | |||
| if( theZipFile != null ) | |||
| { | |||
| try | |||
| { | |||
| theZipFile.close(); | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| //ignore | |||
| } | |||
| } | |||
| } | |||
| } | |||
| else if( manifestFile.lastModified() > zipFile.lastModified() ) | |||
| { | |||
| return false; | |||
| } | |||
| return super.isUpToDate( scanners, zipFile ); | |||
| } | |||
| /** | |||
| * Make sure we don't think we already have a MANIFEST next time this task | |||
| * gets executed. | |||
| */ | |||
| protected void cleanUp() | |||
| { | |||
| super.cleanUp(); | |||
| } | |||
| protected boolean createEmptyZip( File zipFile ) | |||
| { | |||
| // Jar files always contain a manifest and can never be empty | |||
| return false; | |||
| } | |||
| protected void finalizeZipOutputStream( ZipOutputStream zOut ) | |||
| throws IOException, BuildException | |||
| { | |||
| if( index ) | |||
| { | |||
| createIndexList( zOut ); | |||
| } | |||
| } | |||
| protected void initZipOutputStream( ZipOutputStream zOut ) | |||
| throws IOException, BuildException | |||
| { | |||
| try | |||
| { | |||
| execManifest = Manifest.getDefaultManifest(); | |||
| if( manifest != null ) | |||
| { | |||
| execManifest.merge( manifest ); | |||
| } | |||
| for( Enumeration e = execManifest.getWarnings(); e.hasMoreElements(); ) | |||
| { | |||
| log( "Manifest warning: " + ( String )e.nextElement(), Project.MSG_WARN ); | |||
| } | |||
| zipDir( null, zOut, "META-INF/" ); | |||
| // time to write the manifest | |||
| ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |||
| PrintWriter writer = new PrintWriter( baos ); | |||
| execManifest.write( writer ); | |||
| writer.flush(); | |||
| ByteArrayInputStream bais = new ByteArrayInputStream( baos.toByteArray() ); | |||
| super.zipFile( bais, zOut, "META-INF/MANIFEST.MF", System.currentTimeMillis() ); | |||
| super.initZipOutputStream( zOut ); | |||
| } | |||
| catch( ManifestException e ) | |||
| { | |||
| log( "Manifest is invalid: " + e.getMessage(), Project.MSG_ERR ); | |||
| throw new BuildException( "Invalid Manifest", e, getLocation() ); | |||
| } | |||
| } | |||
| protected void zipFile( File file, ZipOutputStream zOut, String vPath ) | |||
| throws IOException | |||
| { | |||
| // If the file being added is META-INF/MANIFEST.MF, we warn if it's not the | |||
| // one specified in the "manifest" attribute - or if it's being added twice, | |||
| // meaning the same file is specified by the "manifeset" attribute and in | |||
| // a <fileset> element. | |||
| if( vPath.equalsIgnoreCase( "META-INF/MANIFEST.MF" ) ) | |||
| { | |||
| log( "Warning: selected " + archiveType + " files include a META-INF/MANIFEST.MF which will be ignored " + | |||
| "(please use manifest attribute to " + archiveType + " task)", Project.MSG_WARN ); | |||
| } | |||
| else | |||
| { | |||
| super.zipFile( file, zOut, vPath ); | |||
| } | |||
| } | |||
| protected void zipFile( InputStream is, ZipOutputStream zOut, String vPath, long lastModified ) | |||
| throws IOException | |||
| { | |||
| // If the file being added is META-INF/MANIFEST.MF, we merge it with the | |||
| // current manifest | |||
| if( vPath.equalsIgnoreCase( "META-INF/MANIFEST.MF" ) ) | |||
| { | |||
| try | |||
| { | |||
| zipManifestEntry( is ); | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| throw new BuildException( "Unable to read manifest file: ", e ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| super.zipFile( is, zOut, vPath, lastModified ); | |||
| } | |||
| } | |||
| /** | |||
| * Create the index list to speed up classloading. This is a JDK 1.3+ | |||
| * specific feature and is enabled by default. {@link | |||
| * http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html#JAR%20Index} | |||
| * | |||
| * @param zOut the zip stream representing the jar being built. | |||
| * @throws IOException thrown if there is an error while creating the index | |||
| * and adding it to the zip stream. | |||
| */ | |||
| private void createIndexList( ZipOutputStream zOut ) | |||
| throws IOException | |||
| { | |||
| ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |||
| // encoding must be UTF8 as specified in the specs. | |||
| PrintWriter writer = new PrintWriter( new OutputStreamWriter( baos, "UTF8" ) ); | |||
| // version-info blankline | |||
| writer.println( "JarIndex-Version: 1.0" ); | |||
| writer.println(); | |||
| // header newline | |||
| writer.println( zipFile.getName() ); | |||
| // JarIndex is sorting the directories by ascending order. | |||
| // it's painful to do in JDK 1.1 and it has no value but cosmetic | |||
| // since it will be read into a hashtable by the classloader. | |||
| Enumeration enum = addedDirs.keys(); | |||
| while( enum.hasMoreElements() ) | |||
| { | |||
| String dir = ( String )enum.nextElement(); | |||
| // try to be smart, not to be fooled by a weird directory name | |||
| // @fixme do we need to check for directories starting by ./ ? | |||
| dir = dir.replace( '\\', '/' ); | |||
| int pos = dir.lastIndexOf( '/' ); | |||
| if( pos != -1 ) | |||
| { | |||
| dir = dir.substring( 0, pos ); | |||
| } | |||
| // looks like nothing from META-INF should be added | |||
| // and the check is not case insensitive. | |||
| // see sun.misc.JarIndex | |||
| if( dir.startsWith( "META-INF" ) ) | |||
| { | |||
| continue; | |||
| } | |||
| // name newline | |||
| writer.println( dir ); | |||
| } | |||
| writer.flush(); | |||
| ByteArrayInputStream bais = new ByteArrayInputStream( baos.toByteArray() ); | |||
| super.zipFile( bais, zOut, INDEX_NAME, System.currentTimeMillis() ); | |||
| } | |||
| /** | |||
| * Handle situation when we encounter a manifest file If we haven't been | |||
| * given one, we use this one. If we have, we merge the manifest in, | |||
| * provided it is a new file and not the old one from the JAR we are | |||
| * updating | |||
| * | |||
| * @param is Description of Parameter | |||
| * @exception IOException Description of Exception | |||
| */ | |||
| private void zipManifestEntry( InputStream is ) | |||
| throws IOException | |||
| { | |||
| try | |||
| { | |||
| if( execManifest == null ) | |||
| { | |||
| execManifest = new Manifest( new InputStreamReader( is ) ); | |||
| } | |||
| else if( isAddingNewFiles() ) | |||
| { | |||
| execManifest.merge( new Manifest( new InputStreamReader( is ) ) ); | |||
| } | |||
| } | |||
| catch( ManifestException e ) | |||
| { | |||
| log( "Manifest is invalid: " + e.getMessage(), Project.MSG_ERR ); | |||
| throw new BuildException( "Invalid Manifest", e, getLocation() ); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,456 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.File; | |||
| import java.io.FileOutputStream; | |||
| import java.io.IOException; | |||
| import java.io.PrintStream; | |||
| import java.util.Vector; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.ExitException; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.Task; | |||
| import org.apache.tools.ant.types.Commandline; | |||
| import org.apache.tools.ant.types.CommandlineJava; | |||
| import org.apache.tools.ant.types.Environment; | |||
| import org.apache.tools.ant.types.Path; | |||
| import org.apache.tools.ant.types.Reference; | |||
| /** | |||
| * This task acts as a loader for java applications but allows to use the same | |||
| * JVM for the called application thus resulting in much faster operation. | |||
| * | |||
| * @author Stefano Mazzocchi <a href="mailto:stefano@apache.org"> | |||
| * stefano@apache.org</a> | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| */ | |||
| public class Java extends Task | |||
| { | |||
| private CommandlineJava cmdl = new CommandlineJava(); | |||
| private boolean fork = false; | |||
| private File dir = null; | |||
| private PrintStream outStream = null; | |||
| private boolean failOnError = false; | |||
| private File out; | |||
| /** | |||
| * Set the command line arguments for the class. | |||
| * | |||
| * @param s The new Args value | |||
| */ | |||
| public void setArgs( String s ) | |||
| { | |||
| log( "The args attribute is deprecated. " + | |||
| "Please use nested arg elements.", | |||
| Project.MSG_WARN ); | |||
| cmdl.createArgument().setLine( s ); | |||
| } | |||
| /** | |||
| * Set the class name. | |||
| * | |||
| * @param s The new Classname value | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| public void setClassname( String s ) | |||
| throws BuildException | |||
| { | |||
| if( cmdl.getJar() != null ) | |||
| { | |||
| throw new BuildException( "Cannot use 'jar' and 'classname' attributes in same command" ); | |||
| } | |||
| cmdl.setClassname( s ); | |||
| } | |||
| /** | |||
| * Set the classpath to be used for this compilation. | |||
| * | |||
| * @param s The new Classpath value | |||
| */ | |||
| public void setClasspath( Path s ) | |||
| { | |||
| createClasspath().append( s ); | |||
| } | |||
| /** | |||
| * Adds a reference to a CLASSPATH defined elsewhere. | |||
| * | |||
| * @param r The new ClasspathRef value | |||
| */ | |||
| public void setClasspathRef( Reference r ) | |||
| { | |||
| createClasspath().setRefid( r ); | |||
| } | |||
| /** | |||
| * The working directory of the process | |||
| * | |||
| * @param d The new Dir value | |||
| */ | |||
| public void setDir( File d ) | |||
| { | |||
| this.dir = d; | |||
| } | |||
| /** | |||
| * Throw a BuildException if process returns non 0. | |||
| * | |||
| * @param fail The new Failonerror value | |||
| */ | |||
| public void setFailonerror( boolean fail ) | |||
| { | |||
| failOnError = fail; | |||
| } | |||
| /** | |||
| * Set the forking flag. | |||
| * | |||
| * @param s The new Fork value | |||
| */ | |||
| public void setFork( boolean s ) | |||
| { | |||
| this.fork = s; | |||
| } | |||
| public void setJVMVersion( String value ) | |||
| { | |||
| cmdl.setVmversion( value ); | |||
| } | |||
| /** | |||
| * set the jar name... | |||
| * | |||
| * @param jarfile The new Jar value | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| public void setJar( File jarfile ) | |||
| throws BuildException | |||
| { | |||
| if( cmdl.getClassname() != null ) | |||
| { | |||
| throw new BuildException( "Cannot use 'jar' and 'classname' attributes in same command." ); | |||
| } | |||
| cmdl.setJar( jarfile.getAbsolutePath() ); | |||
| } | |||
| /** | |||
| * Set the command used to start the VM (only if fork==false). | |||
| * | |||
| * @param s The new Jvm value | |||
| */ | |||
| public void setJvm( String s ) | |||
| { | |||
| cmdl.setVm( s ); | |||
| } | |||
| /** | |||
| * Set the command line arguments for the JVM. | |||
| * | |||
| * @param s The new Jvmargs value | |||
| */ | |||
| public void setJvmargs( String s ) | |||
| { | |||
| log( "The jvmargs attribute is deprecated. " + | |||
| "Please use nested jvmarg elements.", | |||
| Project.MSG_WARN ); | |||
| cmdl.createVmArgument().setLine( s ); | |||
| } | |||
| /** | |||
| * -mx or -Xmx depending on VM version | |||
| * | |||
| * @param max The new Maxmemory value | |||
| */ | |||
| public void setMaxmemory( String max ) | |||
| { | |||
| cmdl.setMaxmemory( max ); | |||
| } | |||
| /** | |||
| * File the output of the process is redirected to. | |||
| * | |||
| * @param out The new Output value | |||
| */ | |||
| public void setOutput( File out ) | |||
| { | |||
| this.out = out; | |||
| } | |||
| /** | |||
| * Add a nested sysproperty element. | |||
| * | |||
| * @param sysp The feature to be added to the Sysproperty attribute | |||
| */ | |||
| public void addSysproperty( Environment.Variable sysp ) | |||
| { | |||
| cmdl.addSysproperty( sysp ); | |||
| } | |||
| /** | |||
| * Clear out the arguments to this java task. | |||
| */ | |||
| public void clearArgs() | |||
| { | |||
| cmdl.clearJavaArgs(); | |||
| } | |||
| /** | |||
| * Creates a nested arg element. | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public Commandline.Argument createArg() | |||
| { | |||
| return cmdl.createArgument(); | |||
| } | |||
| /** | |||
| * Creates a nested classpath element | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public Path createClasspath() | |||
| { | |||
| return cmdl.createClasspath( project ).createPath(); | |||
| } | |||
| /** | |||
| * Creates a nested jvmarg element. | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public Commandline.Argument createJvmarg() | |||
| { | |||
| return cmdl.createVmArgument(); | |||
| } | |||
| /** | |||
| * Do the execution. | |||
| * | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| int err = -1; | |||
| if( ( err = executeJava() ) != 0 ) | |||
| { | |||
| if( failOnError ) | |||
| { | |||
| throw new BuildException( "Java returned: " + err, location ); | |||
| } | |||
| else | |||
| { | |||
| log( "Java Result: " + err, Project.MSG_ERR ); | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Do the execution and return a return code. | |||
| * | |||
| * @return the return code from the execute java class if it was executed in | |||
| * a separate VM (fork = "yes"). | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| public int executeJava() | |||
| throws BuildException | |||
| { | |||
| String classname = cmdl.getClassname(); | |||
| if( classname == null && cmdl.getJar() == null ) | |||
| { | |||
| throw new BuildException( "Classname must not be null." ); | |||
| } | |||
| if( !fork && cmdl.getJar() != null ) | |||
| { | |||
| throw new BuildException( "Cannot execute a jar in non-forked mode. Please set fork='true'. " ); | |||
| } | |||
| if( fork ) | |||
| { | |||
| log( "Forking " + cmdl.toString(), Project.MSG_VERBOSE ); | |||
| return run( cmdl.getCommandline() ); | |||
| } | |||
| else | |||
| { | |||
| if( cmdl.getVmCommand().size() > 1 ) | |||
| { | |||
| log( "JVM args ignored when same JVM is used.", Project.MSG_WARN ); | |||
| } | |||
| if( dir != null ) | |||
| { | |||
| log( "Working directory ignored when same JVM is used.", Project.MSG_WARN ); | |||
| } | |||
| log( "Running in same VM " + cmdl.getJavaCommand().toString(), | |||
| Project.MSG_VERBOSE ); | |||
| try | |||
| { | |||
| run( cmdl ); | |||
| return 0; | |||
| } | |||
| catch( ExitException ex ) | |||
| { | |||
| return ex.getStatus(); | |||
| } | |||
| } | |||
| } | |||
| protected void handleErrorOutput( String line ) | |||
| { | |||
| if( outStream != null ) | |||
| { | |||
| outStream.println( line ); | |||
| } | |||
| else | |||
| { | |||
| super.handleErrorOutput( line ); | |||
| } | |||
| } | |||
| protected void handleOutput( String line ) | |||
| { | |||
| if( outStream != null ) | |||
| { | |||
| outStream.println( line ); | |||
| } | |||
| else | |||
| { | |||
| super.handleOutput( line ); | |||
| } | |||
| } | |||
| /** | |||
| * Executes the given classname with the given arguments as it was a command | |||
| * line application. | |||
| * | |||
| * @param classname Description of Parameter | |||
| * @param args Description of Parameter | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| protected void run( String classname, Vector args ) | |||
| throws BuildException | |||
| { | |||
| CommandlineJava cmdj = new CommandlineJava(); | |||
| cmdj.setClassname( classname ); | |||
| for( int i = 0; i < args.size(); i++ ) | |||
| { | |||
| cmdj.createArgument().setValue( ( String )args.elementAt( i ) ); | |||
| } | |||
| run( cmdj ); | |||
| } | |||
| /** | |||
| * Executes the given classname with the given arguments as it was a command | |||
| * line application. | |||
| * | |||
| * @param command Description of Parameter | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| private void run( CommandlineJava command ) | |||
| throws BuildException | |||
| { | |||
| ExecuteJava exe = new ExecuteJava(); | |||
| exe.setJavaCommand( command.getJavaCommand() ); | |||
| exe.setClasspath( command.getClasspath() ); | |||
| exe.setSystemProperties( command.getSystemProperties() ); | |||
| if( out != null ) | |||
| { | |||
| try | |||
| { | |||
| outStream = new PrintStream( new FileOutputStream( out ) ); | |||
| exe.execute( project ); | |||
| } | |||
| catch( IOException io ) | |||
| { | |||
| throw new BuildException( io ); | |||
| } | |||
| finally | |||
| { | |||
| if( outStream != null ) | |||
| { | |||
| outStream.close(); | |||
| } | |||
| } | |||
| } | |||
| else | |||
| { | |||
| exe.execute( project ); | |||
| } | |||
| } | |||
| /** | |||
| * Executes the given classname with the given arguments in a separate VM. | |||
| * | |||
| * @param command Description of Parameter | |||
| * @return Description of the Returned Value | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| private int run( String[] command ) | |||
| throws BuildException | |||
| { | |||
| FileOutputStream fos = null; | |||
| try | |||
| { | |||
| Execute exe = null; | |||
| if( out == null ) | |||
| { | |||
| exe = new Execute( new LogStreamHandler( this, Project.MSG_INFO, | |||
| Project.MSG_WARN ), | |||
| null ); | |||
| } | |||
| else | |||
| { | |||
| fos = new FileOutputStream( out ); | |||
| exe = new Execute( new PumpStreamHandler( fos ), null ); | |||
| } | |||
| exe.setAntRun( project ); | |||
| if( dir == null ) | |||
| { | |||
| dir = project.getBaseDir(); | |||
| } | |||
| else if( !dir.exists() || !dir.isDirectory() ) | |||
| { | |||
| throw new BuildException( dir.getAbsolutePath() + " is not a valid directory", | |||
| location ); | |||
| } | |||
| exe.setWorkingDirectory( dir ); | |||
| exe.setCommandline( command ); | |||
| try | |||
| { | |||
| return exe.execute(); | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| throw new BuildException( e ); | |||
| } | |||
| } | |||
| catch( IOException io ) | |||
| { | |||
| throw new BuildException( io ); | |||
| } | |||
| finally | |||
| { | |||
| if( fos != null ) | |||
| { | |||
| try | |||
| { | |||
| fos.close(); | |||
| } | |||
| catch( IOException io ) | |||
| {} | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,941 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.File; | |||
| import java.util.Enumeration; | |||
| 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.compilers.CompilerAdapter; | |||
| import org.apache.tools.ant.taskdefs.compilers.CompilerAdapterFactory; | |||
| import org.apache.myrmidon.framework.Os; | |||
| import org.apache.tools.ant.types.Commandline; | |||
| import org.apache.tools.ant.types.Path; | |||
| import org.apache.tools.ant.types.Reference; | |||
| import org.apache.tools.ant.util.GlobPatternMapper; | |||
| import org.apache.tools.ant.util.SourceFileScanner; | |||
| /** | |||
| * Task to compile Java source files. This task can take the following | |||
| * arguments: | |||
| * <ul> | |||
| * <li> sourcedir | |||
| * <li> destdir | |||
| * <li> deprecation | |||
| * <li> classpath | |||
| * <li> bootclasspath | |||
| * <li> extdirs | |||
| * <li> optimize | |||
| * <li> debug | |||
| * <li> encoding | |||
| * <li> target | |||
| * <li> depend | |||
| * <li> vebose | |||
| * <li> failonerror | |||
| * <li> includeantruntime | |||
| * <li> includejavaruntime | |||
| * <li> source | |||
| * </ul> | |||
| * Of these arguments, the <b>sourcedir</b> and <b>destdir</b> are required. <p> | |||
| * | |||
| * When this task executes, it will recursively scan the sourcedir and destdir | |||
| * looking for Java source files to compile. This task makes its compile | |||
| * decision based on timestamp. | |||
| * | |||
| * @author James Davidson <a href="mailto:duncan@x180.com">duncan@x180.com</a> | |||
| * @author Robin Green <a href="mailto:greenrd@hotmail.com">greenrd@hotmail.com | |||
| * </a> | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| * @author <a href="mailto:jayglanville@home.com">J D Glanville</a> | |||
| */ | |||
| public class Javac extends MatchingTask | |||
| { | |||
| private final static String FAIL_MSG | |||
| = "Compile failed, messages should have been provided."; | |||
| private boolean debug = false; | |||
| private boolean optimize = false; | |||
| private boolean deprecation = false; | |||
| private boolean depend = false; | |||
| private boolean verbose = false; | |||
| private boolean includeAntRuntime = true; | |||
| private boolean includeJavaRuntime = false; | |||
| private String fork = "false"; | |||
| private String forkedExecutable = null; | |||
| private boolean nowarn = false; | |||
| private Vector implementationSpecificArgs = new Vector(); | |||
| protected boolean failOnError = true; | |||
| protected File[] compileList = new File[0]; | |||
| private Path bootclasspath; | |||
| private Path compileClasspath; | |||
| private String debugLevel; | |||
| private File destDir; | |||
| private String encoding; | |||
| private Path extdirs; | |||
| private String memoryInitialSize; | |||
| private String memoryMaximumSize; | |||
| private String source; | |||
| private Path src; | |||
| private String target; | |||
| /** | |||
| * Adds a reference to a CLASSPATH defined elsewhere. | |||
| * | |||
| * @param r The new BootClasspathRef value | |||
| */ | |||
| public void setBootClasspathRef( Reference r ) | |||
| { | |||
| createBootclasspath().setRefid( r ); | |||
| } | |||
| /** | |||
| * Sets the bootclasspath that will be used to compile the classes against. | |||
| * | |||
| * @param bootclasspath The new Bootclasspath value | |||
| */ | |||
| public void setBootclasspath( Path bootclasspath ) | |||
| { | |||
| if( this.bootclasspath == null ) | |||
| { | |||
| this.bootclasspath = bootclasspath; | |||
| } | |||
| else | |||
| { | |||
| this.bootclasspath.append( bootclasspath ); | |||
| } | |||
| } | |||
| /** | |||
| * Set the classpath to be used for this compilation. | |||
| * | |||
| * @param classpath The new Classpath value | |||
| */ | |||
| public void setClasspath( Path classpath ) | |||
| { | |||
| if( compileClasspath == null ) | |||
| { | |||
| compileClasspath = classpath; | |||
| } | |||
| else | |||
| { | |||
| compileClasspath.append( classpath ); | |||
| } | |||
| } | |||
| /** | |||
| * Adds a reference to a CLASSPATH defined elsewhere. | |||
| * | |||
| * @param r The new ClasspathRef value | |||
| */ | |||
| public void setClasspathRef( Reference r ) | |||
| { | |||
| createClasspath().setRefid( r ); | |||
| } | |||
| /** | |||
| * Set the debug flag. | |||
| * | |||
| * @param debug The new Debug value | |||
| */ | |||
| public void setDebug( boolean debug ) | |||
| { | |||
| this.debug = debug; | |||
| } | |||
| /** | |||
| * Set the value of debugLevel. | |||
| * | |||
| * @param v Value to assign to debugLevel. | |||
| */ | |||
| public void setDebugLevel( String v ) | |||
| { | |||
| this.debugLevel = v; | |||
| } | |||
| /** | |||
| * Set the depend flag. | |||
| * | |||
| * @param depend The new Depend value | |||
| */ | |||
| public void setDepend( boolean depend ) | |||
| { | |||
| this.depend = depend; | |||
| } | |||
| /** | |||
| * Set the deprecation flag. | |||
| * | |||
| * @param deprecation The new Deprecation value | |||
| */ | |||
| public void setDeprecation( boolean deprecation ) | |||
| { | |||
| this.deprecation = deprecation; | |||
| } | |||
| /** | |||
| * Set the destination directory into which the Java source files should be | |||
| * compiled. | |||
| * | |||
| * @param destDir The new Destdir value | |||
| */ | |||
| public void setDestdir( File destDir ) | |||
| { | |||
| this.destDir = destDir; | |||
| } | |||
| /** | |||
| * Set the Java source file encoding name. | |||
| * | |||
| * @param encoding The new Encoding value | |||
| */ | |||
| public void setEncoding( String encoding ) | |||
| { | |||
| this.encoding = encoding; | |||
| } | |||
| /** | |||
| * Sets the extension directories that will be used during the compilation. | |||
| * | |||
| * @param extdirs The new Extdirs value | |||
| */ | |||
| public void setExtdirs( Path extdirs ) | |||
| { | |||
| if( this.extdirs == null ) | |||
| { | |||
| this.extdirs = extdirs; | |||
| } | |||
| else | |||
| { | |||
| this.extdirs.append( extdirs ); | |||
| } | |||
| } | |||
| /** | |||
| * Throw a BuildException if compilation fails | |||
| * | |||
| * @param fail The new Failonerror value | |||
| */ | |||
| public void setFailonerror( boolean fail ) | |||
| { | |||
| failOnError = fail; | |||
| } | |||
| /** | |||
| * Sets whether to fork the javac compiler. | |||
| * | |||
| * @param f "true|false|on|off|yes|no" or the name of the javac executable. | |||
| */ | |||
| public void setFork( String f ) | |||
| { | |||
| if( f.equalsIgnoreCase( "on" ) | |||
| || f.equalsIgnoreCase( "true" ) | |||
| || f.equalsIgnoreCase( "yes" ) ) | |||
| { | |||
| fork = "true"; | |||
| forkedExecutable = getSystemJavac(); | |||
| } | |||
| else if( f.equalsIgnoreCase( "off" ) | |||
| || f.equalsIgnoreCase( "false" ) | |||
| || f.equalsIgnoreCase( "no" ) ) | |||
| { | |||
| fork = "false"; | |||
| forkedExecutable = null; | |||
| } | |||
| else | |||
| { | |||
| fork = "true"; | |||
| forkedExecutable = f; | |||
| } | |||
| } | |||
| /** | |||
| * Include ant's own classpath in this task's classpath? | |||
| * | |||
| * @param include The new Includeantruntime value | |||
| */ | |||
| public void setIncludeantruntime( boolean include ) | |||
| { | |||
| includeAntRuntime = include; | |||
| } | |||
| /** | |||
| * Sets whether or not to include the java runtime libraries to this task's | |||
| * classpath. | |||
| * | |||
| * @param include The new Includejavaruntime value | |||
| */ | |||
| public void setIncludejavaruntime( boolean include ) | |||
| { | |||
| includeJavaRuntime = include; | |||
| } | |||
| /** | |||
| * Set the memoryInitialSize flag. | |||
| * | |||
| * @param memoryInitialSize The new MemoryInitialSize value | |||
| */ | |||
| public void setMemoryInitialSize( String memoryInitialSize ) | |||
| { | |||
| this.memoryInitialSize = memoryInitialSize; | |||
| } | |||
| /** | |||
| * Set the memoryMaximumSize flag. | |||
| * | |||
| * @param memoryMaximumSize The new MemoryMaximumSize value | |||
| */ | |||
| public void setMemoryMaximumSize( String memoryMaximumSize ) | |||
| { | |||
| this.memoryMaximumSize = memoryMaximumSize; | |||
| } | |||
| /** | |||
| * Sets whether the -nowarn option should be used. | |||
| * | |||
| * @param flag The new Nowarn value | |||
| */ | |||
| public void setNowarn( boolean flag ) | |||
| { | |||
| this.nowarn = flag; | |||
| } | |||
| /** | |||
| * Set the optimize flag. | |||
| * | |||
| * @param optimize The new Optimize value | |||
| */ | |||
| public void setOptimize( boolean optimize ) | |||
| { | |||
| this.optimize = optimize; | |||
| } | |||
| /** | |||
| * Proceed if compilation fails | |||
| * | |||
| * @param proceed The new Proceed value | |||
| */ | |||
| public void setProceed( boolean proceed ) | |||
| { | |||
| failOnError = !proceed; | |||
| } | |||
| /** | |||
| * Set the value of source. | |||
| * | |||
| * @param v Value to assign to source. | |||
| */ | |||
| public void setSource( String v ) | |||
| { | |||
| this.source = v; | |||
| } | |||
| /** | |||
| * Set the source dirs to find the source Java files. | |||
| * | |||
| * @param srcDir The new Srcdir value | |||
| */ | |||
| public void setSrcdir( Path srcDir ) | |||
| { | |||
| if( src == null ) | |||
| { | |||
| src = srcDir; | |||
| } | |||
| else | |||
| { | |||
| src.append( srcDir ); | |||
| } | |||
| } | |||
| /** | |||
| * Sets the target VM that the classes will be compiled for. Valid strings | |||
| * are "1.1", "1.2", and "1.3". | |||
| * | |||
| * @param target The new Target value | |||
| */ | |||
| public void setTarget( String target ) | |||
| { | |||
| this.target = target; | |||
| } | |||
| /** | |||
| * Set the verbose flag. | |||
| * | |||
| * @param verbose The new Verbose value | |||
| */ | |||
| public void setVerbose( boolean verbose ) | |||
| { | |||
| this.verbose = verbose; | |||
| } | |||
| /** | |||
| * Gets the bootclasspath that will be used to compile the classes against. | |||
| * | |||
| * @return The Bootclasspath value | |||
| */ | |||
| public Path getBootclasspath() | |||
| { | |||
| return bootclasspath; | |||
| } | |||
| /** | |||
| * Gets the classpath to be used for this compilation. | |||
| * | |||
| * @return The Classpath value | |||
| */ | |||
| public Path getClasspath() | |||
| { | |||
| return compileClasspath; | |||
| } | |||
| /** | |||
| * Get the additional implementation specific command line arguments. | |||
| * | |||
| * @return array of command line arguments, guaranteed to be non-null. | |||
| */ | |||
| public String[] getCurrentCompilerArgs() | |||
| { | |||
| Vector args = new Vector(); | |||
| for( Enumeration enum = implementationSpecificArgs.elements(); | |||
| enum.hasMoreElements(); | |||
| ) | |||
| { | |||
| String[] curr = | |||
| ( ( ImplementationSpecificArgument )enum.nextElement() ).getParts(); | |||
| for( int i = 0; i < curr.length; i++ ) | |||
| { | |||
| args.addElement( curr[i] ); | |||
| } | |||
| } | |||
| String[] res = new String[args.size()]; | |||
| args.copyInto( res ); | |||
| return res; | |||
| } | |||
| /** | |||
| * Gets the debug flag. | |||
| * | |||
| * @return The Debug value | |||
| */ | |||
| public boolean getDebug() | |||
| { | |||
| return debug; | |||
| } | |||
| /** | |||
| * Get the value of debugLevel. | |||
| * | |||
| * @return value of debugLevel. | |||
| */ | |||
| public String getDebugLevel() | |||
| { | |||
| return debugLevel; | |||
| } | |||
| /** | |||
| * Gets the depend flag. | |||
| * | |||
| * @return The Depend value | |||
| */ | |||
| public boolean getDepend() | |||
| { | |||
| return depend; | |||
| } | |||
| /** | |||
| * Gets the deprecation flag. | |||
| * | |||
| * @return The Deprecation value | |||
| */ | |||
| public boolean getDeprecation() | |||
| { | |||
| return deprecation; | |||
| } | |||
| /** | |||
| * Gets the destination directory into which the java source files should be | |||
| * compiled. | |||
| * | |||
| * @return The Destdir value | |||
| */ | |||
| public File getDestdir() | |||
| { | |||
| return destDir; | |||
| } | |||
| /** | |||
| * Gets the java source file encoding name. | |||
| * | |||
| * @return The Encoding value | |||
| */ | |||
| public String getEncoding() | |||
| { | |||
| return encoding; | |||
| } | |||
| /** | |||
| * Gets the extension directories that will be used during the compilation. | |||
| * | |||
| * @return The Extdirs value | |||
| */ | |||
| public Path getExtdirs() | |||
| { | |||
| return extdirs; | |||
| } | |||
| /** | |||
| * Gets the failonerror flag. | |||
| * | |||
| * @return The Failonerror value | |||
| */ | |||
| public boolean getFailonerror() | |||
| { | |||
| return failOnError; | |||
| } | |||
| /** | |||
| * Gets the list of files to be compiled. | |||
| * | |||
| * @return The FileList value | |||
| */ | |||
| public File[] getFileList() | |||
| { | |||
| return compileList; | |||
| } | |||
| /** | |||
| * Gets whether or not the ant classpath is to be included in the task's | |||
| * classpath. | |||
| * | |||
| * @return The Includeantruntime value | |||
| */ | |||
| public boolean getIncludeantruntime() | |||
| { | |||
| return includeAntRuntime; | |||
| } | |||
| /** | |||
| * Gets whether or not the java runtime should be included in this task's | |||
| * classpath. | |||
| * | |||
| * @return The Includejavaruntime value | |||
| */ | |||
| public boolean getIncludejavaruntime() | |||
| { | |||
| return includeJavaRuntime; | |||
| } | |||
| /** | |||
| * The name of the javac executable to use in fork-mode. | |||
| * | |||
| * @return The JavacExecutable value | |||
| */ | |||
| public String getJavacExecutable() | |||
| { | |||
| if( forkedExecutable == null && isForkedJavac() ) | |||
| { | |||
| forkedExecutable = getSystemJavac(); | |||
| } | |||
| else if( forkedExecutable != null && !isForkedJavac() ) | |||
| { | |||
| forkedExecutable = null; | |||
| } | |||
| return forkedExecutable; | |||
| } | |||
| /** | |||
| * Gets the memoryInitialSize flag. | |||
| * | |||
| * @return The MemoryInitialSize value | |||
| */ | |||
| public String getMemoryInitialSize() | |||
| { | |||
| return memoryInitialSize; | |||
| } | |||
| /** | |||
| * Gets the memoryMaximumSize flag. | |||
| * | |||
| * @return The MemoryMaximumSize value | |||
| */ | |||
| public String getMemoryMaximumSize() | |||
| { | |||
| return memoryMaximumSize; | |||
| } | |||
| /** | |||
| * Should the -nowarn option be used. | |||
| * | |||
| * @return The Nowarn value | |||
| */ | |||
| public boolean getNowarn() | |||
| { | |||
| return nowarn; | |||
| } | |||
| /** | |||
| * Gets the optimize flag. | |||
| * | |||
| * @return The Optimize value | |||
| */ | |||
| public boolean getOptimize() | |||
| { | |||
| return optimize; | |||
| } | |||
| /** | |||
| * Get the value of source. | |||
| * | |||
| * @return value of source. | |||
| */ | |||
| public String getSource() | |||
| { | |||
| return source; | |||
| } | |||
| /** | |||
| * Gets the source dirs to find the source java files. | |||
| * | |||
| * @return The Srcdir value | |||
| */ | |||
| public Path getSrcdir() | |||
| { | |||
| return src; | |||
| } | |||
| /** | |||
| * Gets the target VM that the classes will be compiled for. | |||
| * | |||
| * @return The Target value | |||
| */ | |||
| public String getTarget() | |||
| { | |||
| return target; | |||
| } | |||
| /** | |||
| * Gets the verbose flag. | |||
| * | |||
| * @return The Verbose value | |||
| */ | |||
| public boolean getVerbose() | |||
| { | |||
| return verbose; | |||
| } | |||
| /** | |||
| * Is this a forked invocation of JDK's javac? | |||
| * | |||
| * @return The ForkedJavac value | |||
| */ | |||
| public boolean isForkedJavac() | |||
| { | |||
| return !"false".equals( fork ) || | |||
| "extJavac".equals( project.getProperty( "build.compiler" ) ); | |||
| } | |||
| /** | |||
| * Maybe creates a nested classpath element. | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public Path createBootclasspath() | |||
| { | |||
| if( bootclasspath == null ) | |||
| { | |||
| bootclasspath = new Path( project ); | |||
| } | |||
| return bootclasspath.createPath(); | |||
| } | |||
| /** | |||
| * Maybe creates a nested classpath element. | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public Path createClasspath() | |||
| { | |||
| if( compileClasspath == null ) | |||
| { | |||
| compileClasspath = new Path( project ); | |||
| } | |||
| return compileClasspath.createPath(); | |||
| } | |||
| /** | |||
| * Adds an implementation specific command line argument. | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public ImplementationSpecificArgument createCompilerArg() | |||
| { | |||
| ImplementationSpecificArgument arg = | |||
| new ImplementationSpecificArgument(); | |||
| implementationSpecificArgs.addElement( arg ); | |||
| return arg; | |||
| } | |||
| /** | |||
| * Maybe creates a nested classpath element. | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public Path createExtdirs() | |||
| { | |||
| if( extdirs == null ) | |||
| { | |||
| extdirs = new Path( project ); | |||
| } | |||
| return extdirs.createPath(); | |||
| } | |||
| /** | |||
| * Create a nested src element for multiple source path support. | |||
| * | |||
| * @return a nested src element. | |||
| */ | |||
| public Path createSrc() | |||
| { | |||
| if( src == null ) | |||
| { | |||
| src = new Path( project ); | |||
| } | |||
| return src.createPath(); | |||
| } | |||
| /** | |||
| * Executes the task. | |||
| * | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| // first off, make sure that we've got a srcdir | |||
| if( src == null ) | |||
| { | |||
| throw new BuildException( "srcdir attribute must be set!", location ); | |||
| } | |||
| String[] list = src.list(); | |||
| if( list.length == 0 ) | |||
| { | |||
| throw new BuildException( "srcdir attribute must be set!", location ); | |||
| } | |||
| if( destDir != null && !destDir.isDirectory() ) | |||
| { | |||
| throw new BuildException( "destination directory \"" + destDir + "\" does not exist or is not a directory", location ); | |||
| } | |||
| // scan source directories and dest directory to build up | |||
| // compile lists | |||
| resetFileLists(); | |||
| for( int i = 0; i < list.length; i++ ) | |||
| { | |||
| File srcDir = ( File )project.resolveFile( list[i] ); | |||
| if( !srcDir.exists() ) | |||
| { | |||
| throw new BuildException( "srcdir \"" + srcDir.getPath() + "\" does not exist!", location ); | |||
| } | |||
| DirectoryScanner ds = this.getDirectoryScanner( srcDir ); | |||
| String[] files = ds.getIncludedFiles(); | |||
| scanDir( srcDir, destDir != null ? destDir : srcDir, files ); | |||
| } | |||
| // compile the source files | |||
| String compiler = determineCompiler(); | |||
| if( compileList.length > 0 ) | |||
| { | |||
| CompilerAdapter adapter = CompilerAdapterFactory.getCompiler( | |||
| compiler, this ); | |||
| log( "Compiling " + compileList.length + | |||
| " source file" | |||
| + ( compileList.length == 1 ? "" : "s" ) | |||
| + ( destDir != null ? " to " + destDir : "" ) ); | |||
| // now we need to populate the compiler adapter | |||
| adapter.setJavac( this ); | |||
| // finally, lets execute the compiler!! | |||
| if( !adapter.execute() ) | |||
| { | |||
| if( failOnError ) | |||
| { | |||
| throw new BuildException( FAIL_MSG, location ); | |||
| } | |||
| else | |||
| { | |||
| log( FAIL_MSG, Project.MSG_ERR ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| protected String getSystemJavac() | |||
| { | |||
| // This is the most common extension case - exe for windows and OS/2, | |||
| // nothing for *nix. | |||
| String extension = Os.isFamily( "dos" ) ? ".exe" : ""; | |||
| // Look for java in the java.home/../bin directory. Unfortunately | |||
| // on Windows java.home doesn't always refer to the correct location, | |||
| // so we need to fall back to assuming java is somewhere on the | |||
| // PATH. | |||
| java.io.File jExecutable = | |||
| new java.io.File( System.getProperty( "java.home" ) + | |||
| "/../bin/javac" + extension ); | |||
| if( jExecutable.exists() && !Os.isFamily( "netware" ) ) | |||
| { | |||
| return jExecutable.getAbsolutePath(); | |||
| } | |||
| else | |||
| { | |||
| return "javac"; | |||
| } | |||
| } | |||
| protected boolean isJdkCompiler( String compiler ) | |||
| { | |||
| return "modern".equals( compiler ) || | |||
| "classic".equals( compiler ) || | |||
| "javac1.1".equals( compiler ) || | |||
| "javac1.2".equals( compiler ) || | |||
| "javac1.3".equals( compiler ) || | |||
| "javac1.4".equals( compiler ); | |||
| } | |||
| /** | |||
| * Recreate src | |||
| * | |||
| * @return a nested src element. | |||
| */ | |||
| protected Path recreateSrc() | |||
| { | |||
| src = null; | |||
| return createSrc(); | |||
| } | |||
| /** | |||
| * Clear the list of files to be compiled and copied.. | |||
| */ | |||
| protected void resetFileLists() | |||
| { | |||
| compileList = new File[0]; | |||
| } | |||
| /** | |||
| * Scans the directory looking for source files to be compiled. The results | |||
| * are returned in the class variable compileList | |||
| * | |||
| * @param srcDir Description of Parameter | |||
| * @param destDir Description of Parameter | |||
| * @param files Description of Parameter | |||
| */ | |||
| protected void scanDir( File srcDir, File destDir, String files[] ) | |||
| { | |||
| GlobPatternMapper m = new GlobPatternMapper(); | |||
| m.setFrom( "*.java" ); | |||
| m.setTo( "*.class" ); | |||
| SourceFileScanner sfs = new SourceFileScanner( this ); | |||
| File[] newFiles = sfs.restrictAsFiles( files, srcDir, destDir, m ); | |||
| if( newFiles.length > 0 ) | |||
| { | |||
| File[] newCompileList = new File[compileList.length + | |||
| newFiles.length]; | |||
| System.arraycopy( compileList, 0, newCompileList, 0, | |||
| compileList.length ); | |||
| System.arraycopy( newFiles, 0, newCompileList, | |||
| compileList.length, newFiles.length ); | |||
| compileList = newCompileList; | |||
| } | |||
| } | |||
| private String determineCompiler() | |||
| { | |||
| String compiler = project.getProperty( "build.compiler" ); | |||
| if( !"false".equals( fork ) ) | |||
| { | |||
| if( compiler != null ) | |||
| { | |||
| if( isJdkCompiler( compiler ) ) | |||
| { | |||
| log( "Since fork is true, ignoring build.compiler setting.", | |||
| Project.MSG_WARN ); | |||
| compiler = "extJavac"; | |||
| } | |||
| else | |||
| { | |||
| log( "Since build.compiler setting isn't classic or modern, ignoring fork setting.", Project.MSG_WARN ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| compiler = "extJavac"; | |||
| } | |||
| } | |||
| if( compiler == null ) | |||
| { | |||
| if( Project.getJavaVersion() != Project.JAVA_1_1 && | |||
| Project.getJavaVersion() != Project.JAVA_1_2 ) | |||
| { | |||
| compiler = "modern"; | |||
| } | |||
| else | |||
| { | |||
| compiler = "classic"; | |||
| } | |||
| } | |||
| return compiler; | |||
| } | |||
| /** | |||
| * Adds an "implementation" attribute to Commandline$Attribute used to | |||
| * filter command line attributes based on the current implementation. | |||
| * | |||
| * @author RT | |||
| */ | |||
| public class ImplementationSpecificArgument | |||
| extends Commandline.Argument | |||
| { | |||
| private String impl; | |||
| public void setImplementation( String impl ) | |||
| { | |||
| this.impl = impl; | |||
| } | |||
| public String[] getParts() | |||
| { | |||
| if( impl == null || impl.equals( determineCompiler() ) ) | |||
| { | |||
| return super.getParts(); | |||
| } | |||
| else | |||
| { | |||
| return new String[0]; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,95 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.IOException; | |||
| import java.io.OutputStream; | |||
| import org.apache.tools.ant.Task; | |||
| /** | |||
| * Serves as an output stream to Javac. This let's us print messages out to the | |||
| * log and detect whether or not Javac had an error while compiling. | |||
| * | |||
| * @author James Duncan Davidson (duncan@x180.com) | |||
| * @deprecated use returnvalue of compile to detect compilation failure. | |||
| */ | |||
| class JavacOutputStream extends OutputStream | |||
| { | |||
| private boolean errorFlag = false; | |||
| private StringBuffer line; | |||
| private Task task; | |||
| /** | |||
| * Constructs a new JavacOutputStream with the given task as the output | |||
| * source for messages. | |||
| * | |||
| * @param task Description of Parameter | |||
| */ | |||
| JavacOutputStream( Task task ) | |||
| { | |||
| this.task = task; | |||
| 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. | |||
| * | |||
| * @param c Description of Parameter | |||
| * @exception IOException Description of Exception | |||
| */ | |||
| 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 ); | |||
| } | |||
| } | |||
| /** | |||
| * Returns the error status of the compile. If no errors occured, this | |||
| * method will return false, else this method will return true. | |||
| * | |||
| * @return The ErrorFlag value | |||
| */ | |||
| boolean getErrorFlag() | |||
| { | |||
| return errorFlag; | |||
| } | |||
| /** | |||
| * Processes a line of input and determines if an error occured. | |||
| */ | |||
| private void processLine() | |||
| { | |||
| String s = line.toString(); | |||
| if( s.indexOf( "error" ) > -1 ) | |||
| { | |||
| errorFlag = true; | |||
| } | |||
| task.log( s ); | |||
| line = new StringBuffer(); | |||
| } | |||
| } | |||
| @@ -0,0 +1,128 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.File; | |||
| import java.io.FileWriter; | |||
| import java.io.IOException; | |||
| import java.io.PrintWriter; | |||
| import java.util.Random; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Project; | |||
| /** | |||
| * Encapsulates a Jikes compiler, by directly executing an external process. | |||
| * | |||
| * @author skanthak@muehlheim.de | |||
| * @deprecated merged into the class Javac. | |||
| */ | |||
| public class Jikes | |||
| { | |||
| protected String command; | |||
| protected JikesOutputParser jop; | |||
| protected Project project; | |||
| /** | |||
| * Constructs a new Jikes obect. | |||
| * | |||
| * @param jop - Parser to send jike's output to | |||
| * @param command - name of jikes executeable | |||
| * @param project Description of Parameter | |||
| */ | |||
| protected Jikes( JikesOutputParser jop, String command, Project project ) | |||
| { | |||
| super(); | |||
| this.jop = jop; | |||
| this.command = command; | |||
| this.project = project; | |||
| } | |||
| /** | |||
| * Do the compile with the specified arguments. | |||
| * | |||
| * @param args - arguments to pass to process on command line | |||
| */ | |||
| protected void compile( String[] args ) | |||
| { | |||
| String[] commandArray = null; | |||
| File tmpFile = null; | |||
| try | |||
| { | |||
| String myos = System.getProperty( "os.name" ); | |||
| // Windows has a 32k limit on total arg size, so | |||
| // create a temporary file to store all the arguments | |||
| // There have been reports that 300 files could be compiled | |||
| // so 250 is a conservative approach | |||
| if( myos.toLowerCase().indexOf( "windows" ) >= 0 | |||
| && args.length > 250 ) | |||
| { | |||
| PrintWriter out = null; | |||
| try | |||
| { | |||
| tmpFile = new File( "jikes" + ( new Random( System.currentTimeMillis() ) ).nextLong() ); | |||
| out = new PrintWriter( new FileWriter( tmpFile ) ); | |||
| for( int i = 0; i < args.length; i++ ) | |||
| { | |||
| out.println( args[i] ); | |||
| } | |||
| out.flush(); | |||
| commandArray = new String[]{command, | |||
| "@" + tmpFile.getAbsolutePath()}; | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| throw new BuildException( "Error creating temporary file", e ); | |||
| } | |||
| finally | |||
| { | |||
| if( out != null ) | |||
| { | |||
| try | |||
| { | |||
| out.close(); | |||
| } | |||
| catch( Throwable t ) | |||
| {} | |||
| } | |||
| } | |||
| } | |||
| else | |||
| { | |||
| commandArray = new String[args.length + 1]; | |||
| commandArray[0] = command; | |||
| System.arraycopy( args, 0, commandArray, 1, args.length ); | |||
| } | |||
| // We assume, that everything jikes writes goes to | |||
| // standard output, not to standard error. The option | |||
| // -Xstdout that is given to Jikes in Javac.doJikesCompile() | |||
| // should guarantee this. At least I hope so. :) | |||
| try | |||
| { | |||
| Execute exe = new Execute( jop ); | |||
| exe.setAntRun( project ); | |||
| exe.setWorkingDirectory( project.getBaseDir() ); | |||
| exe.setCommandline( commandArray ); | |||
| exe.execute(); | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| throw new BuildException( "Error running Jikes compiler", e ); | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| if( tmpFile != null ) | |||
| { | |||
| tmpFile.delete(); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,174 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.BufferedReader; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.io.InputStreamReader; | |||
| import java.io.OutputStream; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.Task; | |||
| /** | |||
| * Parses output from jikes and passes errors and warnings into the right | |||
| * logging channels of Project. TODO: Parsing could be much better | |||
| * | |||
| * @author skanthak@muehlheim.de | |||
| * @deprecated use Jikes' exit value to detect compilation failure. | |||
| */ | |||
| public class JikesOutputParser implements ExecuteStreamHandler | |||
| { | |||
| protected boolean errorFlag = false; | |||
| protected boolean error = false; | |||
| protected BufferedReader br; | |||
| protected boolean emacsMode;// no errors so far | |||
| protected int errors, warnings; | |||
| protected Task task; | |||
| /** | |||
| * Construct a new Parser object | |||
| * | |||
| * @param task - task in whichs context we are called | |||
| * @param emacsMode Description of Parameter | |||
| */ | |||
| protected JikesOutputParser( Task task, boolean emacsMode ) | |||
| { | |||
| super(); | |||
| this.task = task; | |||
| this.emacsMode = emacsMode; | |||
| } | |||
| /** | |||
| * Ignore. | |||
| * | |||
| * @param is The new ProcessErrorStream value | |||
| */ | |||
| public void setProcessErrorStream( InputStream is ) { } | |||
| /** | |||
| * Ignore. | |||
| * | |||
| * @param os The new ProcessInputStream value | |||
| */ | |||
| public void setProcessInputStream( OutputStream os ) { } | |||
| /** | |||
| * Set the inputstream | |||
| * | |||
| * @param is The new ProcessOutputStream value | |||
| * @exception IOException Description of Exception | |||
| */ | |||
| public void setProcessOutputStream( InputStream is ) | |||
| throws IOException | |||
| { | |||
| br = new BufferedReader( new InputStreamReader( is ) ); | |||
| } | |||
| /** | |||
| * Invokes parseOutput. | |||
| * | |||
| * @exception IOException Description of Exception | |||
| */ | |||
| public void start() | |||
| throws IOException | |||
| { | |||
| parseOutput( br ); | |||
| } | |||
| /** | |||
| * Ignore. | |||
| */ | |||
| public void stop() { } | |||
| /** | |||
| * Indicate if there were errors during the compile | |||
| * | |||
| * @return if errors ocured | |||
| */ | |||
| protected boolean getErrorFlag() | |||
| { | |||
| return errorFlag; | |||
| } | |||
| /** | |||
| * Parse the output of a jikes compiler | |||
| * | |||
| * @param reader - Reader used to read jikes's output | |||
| * @exception IOException Description of Exception | |||
| */ | |||
| protected void parseOutput( BufferedReader reader ) | |||
| throws IOException | |||
| { | |||
| if( emacsMode ) | |||
| parseEmacsOutput( reader ); | |||
| else | |||
| parseStandardOutput( reader ); | |||
| } | |||
| private void setError( boolean err ) | |||
| { | |||
| error = err; | |||
| if( error ) | |||
| errorFlag = true; | |||
| } | |||
| private void log( String line ) | |||
| { | |||
| if( !emacsMode ) | |||
| { | |||
| task.log( "", ( error ? Project.MSG_ERR : Project.MSG_WARN ) ); | |||
| } | |||
| task.log( line, ( error ? Project.MSG_ERR : Project.MSG_WARN ) ); | |||
| } | |||
| private void parseEmacsOutput( BufferedReader reader ) | |||
| throws IOException | |||
| { | |||
| // This may change, if we add advanced parsing capabilities. | |||
| parseStandardOutput( reader ); | |||
| } | |||
| private void parseStandardOutput( BufferedReader reader ) | |||
| throws IOException | |||
| { | |||
| String line; | |||
| String lower; | |||
| // We assume, that every output, jike does, stands for an error/warning | |||
| // XXX | |||
| // Is this correct? | |||
| // TODO: | |||
| // A warning line, that shows code, which contains a variable | |||
| // error will cause some trouble. The parser should definitely | |||
| // be much better. | |||
| while( ( line = reader.readLine() ) != null ) | |||
| { | |||
| lower = line.toLowerCase(); | |||
| if( line.trim().equals( "" ) ) | |||
| continue; | |||
| if( lower.indexOf( "error" ) != -1 ) | |||
| setError( true ); | |||
| else if( lower.indexOf( "warning" ) != -1 ) | |||
| setError( false ); | |||
| else | |||
| { | |||
| // If we don't know the type of the line | |||
| // and we are in emacs mode, it will be | |||
| // an error, because in this mode, jikes won't | |||
| // always print "error", but sometimes other | |||
| // keywords like "Syntax". We should look for | |||
| // all those keywords. | |||
| if( emacsMode ) | |||
| setError( true ); | |||
| } | |||
| log( line ); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,202 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.BufferedReader; | |||
| import java.io.BufferedWriter; | |||
| import java.io.File; | |||
| import java.io.FileReader; | |||
| import java.io.FileWriter; | |||
| import java.io.IOException; | |||
| import java.util.Hashtable; | |||
| import java.util.StringTokenizer; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Task; | |||
| /** | |||
| * Keyword substitution. Input file is written to output file. Do not make input | |||
| * file same as output file. Keywords in input files look like this: | |||
| * | |||
| * @author Jon S. Stevens <a href="mailto:jon@clearink.com">jon@clearink.com</a> | |||
| * @foo@. See the docs for the setKeys method to understand how to do the | |||
| * substitutions. | |||
| * @deprecated KeySubst is deprecated. Use Filter + CopyDir instead. | |||
| */ | |||
| public class KeySubst extends Task | |||
| { | |||
| private File source = null; | |||
| private File dest = null; | |||
| private String sep = "*"; | |||
| private Hashtable replacements = new Hashtable(); | |||
| public static void main( String[] args ) | |||
| { | |||
| try | |||
| { | |||
| Hashtable hash = new Hashtable(); | |||
| hash.put( "VERSION", "1.0.3" ); | |||
| hash.put( "b", "ffff" ); | |||
| System.out.println( KeySubst.replace( "$f ${VERSION} f ${b} jj $", hash ) ); | |||
| } | |||
| catch( Exception e ) | |||
| { | |||
| e.printStackTrace(); | |||
| } | |||
| } | |||
| /** | |||
| * Does replacement on text using the hashtable of keys. | |||
| * | |||
| * @param origString Description of Parameter | |||
| * @param keys Description of Parameter | |||
| * @return Description of the Returned Value | |||
| * @exception BuildException Description of Exception | |||
| * @returns the string with the replacements in it. | |||
| */ | |||
| public static String replace( String origString, Hashtable keys ) | |||
| throws BuildException | |||
| { | |||
| StringBuffer finalString = new StringBuffer(); | |||
| int index = 0; | |||
| int i = 0; | |||
| String key = null; | |||
| while( ( index = origString.indexOf( "${", i ) ) > -1 ) | |||
| { | |||
| key = origString.substring( index + 2, origString.indexOf( "}", index + 3 ) ); | |||
| finalString.append( origString.substring( i, index ) ); | |||
| if( keys.containsKey( key ) ) | |||
| { | |||
| finalString.append( keys.get( key ) ); | |||
| } | |||
| else | |||
| { | |||
| finalString.append( "${" ); | |||
| finalString.append( key ); | |||
| finalString.append( "}" ); | |||
| } | |||
| i = index + 3 + key.length(); | |||
| } | |||
| finalString.append( origString.substring( i ) ); | |||
| return finalString.toString(); | |||
| } | |||
| /** | |||
| * Set the destination file. | |||
| * | |||
| * @param dest The new Dest value | |||
| */ | |||
| public void setDest( File dest ) | |||
| { | |||
| this.dest = dest; | |||
| } | |||
| /** | |||
| * Format string is like this: <p> | |||
| * | |||
| * name=value*name2=value <p> | |||
| * | |||
| * Names are case sensitive. <p> | |||
| * | |||
| * Use the setSep() method to change the * to something else if you need to | |||
| * use * as a name or value. | |||
| * | |||
| * @param keys The new Keys value | |||
| */ | |||
| public void setKeys( String keys ) | |||
| { | |||
| if( keys != null && keys.length() > 0 ) | |||
| { | |||
| StringTokenizer tok = | |||
| new StringTokenizer( keys, this.sep, false ); | |||
| while( tok.hasMoreTokens() ) | |||
| { | |||
| String token = tok.nextToken().trim(); | |||
| StringTokenizer itok = | |||
| new StringTokenizer( token, "=", false ); | |||
| String name = itok.nextToken(); | |||
| String value = itok.nextToken(); | |||
| // log ( "Name: " + name ); | |||
| // log ( "Value: " + value ); | |||
| replacements.put( name, value ); | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Sets the seperator between name=value arguments in setKeys(). By default | |||
| * it is "*". | |||
| * | |||
| * @param sep The new Sep value | |||
| */ | |||
| public void setSep( String sep ) | |||
| { | |||
| this.sep = sep; | |||
| } | |||
| /** | |||
| * Set the source file. | |||
| * | |||
| * @param s The new Src value | |||
| */ | |||
| public void setSrc( File s ) | |||
| { | |||
| this.source = s; | |||
| } | |||
| /** | |||
| * Do the execution. | |||
| * | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| log( "!! KeySubst is deprecated. Use Filter + CopyDir instead. !!" ); | |||
| log( "Performing Substitions" ); | |||
| if( source == null || dest == null ) | |||
| { | |||
| log( "Source and destinations must not be null" ); | |||
| return; | |||
| } | |||
| BufferedReader br = null; | |||
| BufferedWriter bw = null; | |||
| try | |||
| { | |||
| br = new BufferedReader( new FileReader( source ) ); | |||
| dest.delete(); | |||
| bw = new BufferedWriter( new FileWriter( dest ) ); | |||
| String line = null; | |||
| String newline = null; | |||
| int length; | |||
| line = br.readLine(); | |||
| while( line != null ) | |||
| { | |||
| if( line.length() == 0 ) | |||
| { | |||
| bw.newLine(); | |||
| } | |||
| else | |||
| { | |||
| newline = KeySubst.replace( line, replacements ); | |||
| bw.write( newline ); | |||
| bw.newLine(); | |||
| } | |||
| line = br.readLine(); | |||
| } | |||
| bw.flush(); | |||
| bw.close(); | |||
| br.close(); | |||
| } | |||
| catch( IOException ioe ) | |||
| { | |||
| ioe.printStackTrace(); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,116 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.ByteArrayOutputStream; | |||
| import java.io.IOException; | |||
| import java.io.OutputStream; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.Task; | |||
| /** | |||
| * Logs each line written to this stream to the log system of ant. Tries to be | |||
| * smart about line separators.<br> | |||
| * TODO: This class can be split to implement other line based processing of | |||
| * data written to the stream. | |||
| * | |||
| * @author thomas.haas@softwired-inc.com | |||
| */ | |||
| public class LogOutputStream extends OutputStream | |||
| { | |||
| private ByteArrayOutputStream buffer = new ByteArrayOutputStream(); | |||
| private boolean skip = false; | |||
| private int level = Project.MSG_INFO; | |||
| private Task task; | |||
| /** | |||
| * Creates a new instance of this class. | |||
| * | |||
| * @param task the task for whom to log | |||
| * @param level loglevel used to log data written to this stream. | |||
| */ | |||
| public LogOutputStream( Task task, int level ) | |||
| { | |||
| this.task = task; | |||
| this.level = level; | |||
| } | |||
| public int getMessageLevel() | |||
| { | |||
| return level; | |||
| } | |||
| /** | |||
| * Writes all remaining | |||
| * | |||
| * @exception IOException Description of Exception | |||
| */ | |||
| public void close() | |||
| throws IOException | |||
| { | |||
| if( buffer.size() > 0 ) | |||
| processBuffer(); | |||
| super.close(); | |||
| } | |||
| /** | |||
| * Write the data to the buffer and flush the buffer, if a line separator is | |||
| * detected. | |||
| * | |||
| * @param cc data to log (byte). | |||
| * @exception IOException Description of Exception | |||
| */ | |||
| public 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' ); | |||
| } | |||
| /** | |||
| * Converts the buffer to a string and sends it to <code>processLine</code> | |||
| */ | |||
| protected void processBuffer() | |||
| { | |||
| processLine( buffer.toString() ); | |||
| buffer.reset(); | |||
| } | |||
| /** | |||
| * Logs a line to the log system of ant. | |||
| * | |||
| * @param line the line to log. | |||
| */ | |||
| protected void processLine( String line ) | |||
| { | |||
| processLine( line, level ); | |||
| } | |||
| /** | |||
| * Logs a line to the log system of ant. | |||
| * | |||
| * @param line the line to log. | |||
| * @param level Description of Parameter | |||
| */ | |||
| protected void processLine( String line, int level ) | |||
| { | |||
| task.log( line, level ); | |||
| } | |||
| } | |||
| @@ -0,0 +1,48 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.IOException; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Task; | |||
| /** | |||
| * Logs standard output and error of a subprocess to the log system of ant. | |||
| * | |||
| * @author thomas.haas@softwired-inc.com | |||
| */ | |||
| public class LogStreamHandler extends PumpStreamHandler | |||
| { | |||
| /** | |||
| * Creates a new instance of this class. | |||
| * | |||
| * @param task the task for whom to log | |||
| * @param outlevel the loglevel used to log standard output | |||
| * @param errlevel the loglevel used to log standard error | |||
| */ | |||
| public LogStreamHandler( Task task, int outlevel, int errlevel ) | |||
| { | |||
| super( new LogOutputStream( task, outlevel ), | |||
| new LogOutputStream( task, errlevel ) ); | |||
| } | |||
| public void stop() | |||
| { | |||
| super.stop(); | |||
| try | |||
| { | |||
| getErr().close(); | |||
| getOut().close(); | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| // plain impossible | |||
| throw new BuildException( e ); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,950 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.BufferedReader; | |||
| import java.io.File; | |||
| import java.io.FileReader; | |||
| import java.io.FileWriter; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.io.InputStreamReader; | |||
| import java.io.PrintWriter; | |||
| import java.io.Reader; | |||
| import java.io.StringWriter; | |||
| import java.io.UnsupportedEncodingException; | |||
| import java.util.Enumeration; | |||
| import java.util.Hashtable; | |||
| import java.util.Vector; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Task; | |||
| import org.apache.tools.ant.types.EnumeratedAttribute; | |||
| /** | |||
| * Class to manage Manifest information | |||
| * | |||
| * @author <a href="mailto:conor@apache.org">Conor MacNeill</a> | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| */ | |||
| public class Manifest extends Task | |||
| { | |||
| /** | |||
| * The standard manifest version header | |||
| */ | |||
| public final static String ATTRIBUTE_MANIFEST_VERSION = "Manifest-Version"; | |||
| /** | |||
| * The standard Signature Version header | |||
| */ | |||
| public final static String ATTRIBUTE_SIGNATURE_VERSION = "Signature-Version"; | |||
| /** | |||
| * The Name Attribute is the first in a named section | |||
| */ | |||
| public final static String ATTRIBUTE_NAME = "Name"; | |||
| /** | |||
| * The From Header is disallowed in a Manifest | |||
| */ | |||
| public final static String ATTRIBUTE_FROM = "From"; | |||
| /** | |||
| * The Class-Path Header is special - it can be duplicated | |||
| */ | |||
| public final static String ATTRIBUTE_CLASSPATH = "class-path"; | |||
| /** | |||
| * Default Manifest version if one is not specified | |||
| */ | |||
| public final static String DEFAULT_MANIFEST_VERSION = "1.0"; | |||
| /** | |||
| * The max length of a line in a Manifest | |||
| */ | |||
| public final static int MAX_LINE_LENGTH = 70; | |||
| /** | |||
| * The version of this manifest | |||
| */ | |||
| private String manifestVersion = DEFAULT_MANIFEST_VERSION; | |||
| /** | |||
| * The main section of this manifest | |||
| */ | |||
| private Section mainSection = new Section(); | |||
| /** | |||
| * The named sections of this manifest | |||
| */ | |||
| private Hashtable sections = new Hashtable(); | |||
| private File manifestFile; | |||
| private Mode mode; | |||
| /** | |||
| * Construct an empty manifest | |||
| */ | |||
| public Manifest() | |||
| { | |||
| mode = new Mode(); | |||
| mode.setValue( "replace" ); | |||
| manifestVersion = null; | |||
| } | |||
| /** | |||
| * Read a manifest file from the given reader | |||
| * | |||
| * @param r Description of Parameter | |||
| * @exception ManifestException Description of Exception | |||
| * @exception IOException Description of Exception | |||
| * @throws ManifestException if the manifest is not valid according to the | |||
| * JAR spec | |||
| * @throws IOException if the manifest cannot be read from the reader. | |||
| */ | |||
| public Manifest( Reader r ) | |||
| throws ManifestException, IOException | |||
| { | |||
| BufferedReader reader = new BufferedReader( r ); | |||
| // This should be the manifest version | |||
| String nextSectionName = mainSection.read( reader ); | |||
| String readManifestVersion = mainSection.getAttributeValue( ATTRIBUTE_MANIFEST_VERSION ); | |||
| if( readManifestVersion != null ) | |||
| { | |||
| manifestVersion = readManifestVersion; | |||
| mainSection.removeAttribute( ATTRIBUTE_MANIFEST_VERSION ); | |||
| } | |||
| String line = null; | |||
| while( ( line = reader.readLine() ) != null ) | |||
| { | |||
| if( line.length() == 0 ) | |||
| { | |||
| continue; | |||
| } | |||
| Section section = new Section(); | |||
| if( nextSectionName == null ) | |||
| { | |||
| Attribute sectionName = new Attribute( line ); | |||
| if( !sectionName.getName().equalsIgnoreCase( ATTRIBUTE_NAME ) ) | |||
| { | |||
| throw new ManifestException( "Manifest sections should start with a \"" + ATTRIBUTE_NAME + | |||
| "\" attribute and not \"" + sectionName.getName() + "\"" ); | |||
| } | |||
| nextSectionName = sectionName.getValue(); | |||
| } | |||
| else | |||
| { | |||
| // we have already started reading this section | |||
| // this line is the first attribute. set it and then let the normal | |||
| // read handle the rest | |||
| Attribute firstAttribute = new Attribute( line ); | |||
| section.addAttributeAndCheck( firstAttribute ); | |||
| } | |||
| section.setName( nextSectionName ); | |||
| nextSectionName = section.read( reader ); | |||
| addConfiguredSection( section ); | |||
| } | |||
| } | |||
| /** | |||
| * Construct a manifest from Ant's default manifest file. | |||
| * | |||
| * @return The DefaultManifest value | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| public static Manifest getDefaultManifest() | |||
| throws BuildException | |||
| { | |||
| try | |||
| { | |||
| String s = "/org/apache/tools/ant/defaultManifest.mf"; | |||
| InputStream in = Manifest.class.getResourceAsStream( s ); | |||
| if( in == null ) | |||
| { | |||
| throw new BuildException( "Could not find default manifest: " + s ); | |||
| } | |||
| try | |||
| { | |||
| return new Manifest( new InputStreamReader( in, "ASCII" ) ); | |||
| } | |||
| catch( UnsupportedEncodingException e ) | |||
| { | |||
| return new Manifest( new InputStreamReader( in ) ); | |||
| } | |||
| } | |||
| catch( ManifestException e ) | |||
| { | |||
| throw new BuildException( "Default manifest is invalid !!" ); | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| throw new BuildException( "Unable to read default manifest", e ); | |||
| } | |||
| } | |||
| /** | |||
| * The name of the manifest file to write (if used as a task). | |||
| * | |||
| * @param f The new File value | |||
| */ | |||
| public void setFile( File f ) | |||
| { | |||
| manifestFile = f; | |||
| } | |||
| /** | |||
| * Shall we update or replace an existing manifest? | |||
| * | |||
| * @param m The new Mode value | |||
| */ | |||
| public void setMode( Mode m ) | |||
| { | |||
| mode = m; | |||
| } | |||
| /** | |||
| * Get the warnings for this manifest. | |||
| * | |||
| * @return an enumeration of warning strings | |||
| */ | |||
| public Enumeration getWarnings() | |||
| { | |||
| Vector warnings = new Vector(); | |||
| for( Enumeration e2 = mainSection.getWarnings(); e2.hasMoreElements(); ) | |||
| { | |||
| warnings.addElement( e2.nextElement() ); | |||
| } | |||
| // create a vector and add in the warnings for all the sections | |||
| for( Enumeration e = sections.elements(); e.hasMoreElements(); ) | |||
| { | |||
| Section section = ( Section )e.nextElement(); | |||
| for( Enumeration e2 = section.getWarnings(); e2.hasMoreElements(); ) | |||
| { | |||
| warnings.addElement( e2.nextElement() ); | |||
| } | |||
| } | |||
| return warnings.elements(); | |||
| } | |||
| public void addConfiguredAttribute( Attribute attribute ) | |||
| throws ManifestException | |||
| { | |||
| mainSection.addConfiguredAttribute( attribute ); | |||
| } | |||
| public void addConfiguredSection( Section section ) | |||
| throws ManifestException | |||
| { | |||
| if( section.getName() == null ) | |||
| { | |||
| throw new BuildException( "Sections must have a name" ); | |||
| } | |||
| sections.put( section.getName().toLowerCase(), section ); | |||
| } | |||
| public boolean equals( Object rhs ) | |||
| { | |||
| if( !( rhs instanceof Manifest ) ) | |||
| { | |||
| return false; | |||
| } | |||
| Manifest rhsManifest = ( Manifest )rhs; | |||
| if( manifestVersion == null ) | |||
| { | |||
| if( rhsManifest.manifestVersion != null ) | |||
| { | |||
| return false; | |||
| } | |||
| } | |||
| else if( !manifestVersion.equals( rhsManifest.manifestVersion ) ) | |||
| { | |||
| return false; | |||
| } | |||
| if( sections.size() != rhsManifest.sections.size() ) | |||
| { | |||
| return false; | |||
| } | |||
| if( !mainSection.equals( rhsManifest.mainSection ) ) | |||
| { | |||
| return false; | |||
| } | |||
| for( Enumeration e = sections.elements(); e.hasMoreElements(); ) | |||
| { | |||
| Section section = ( Section )e.nextElement(); | |||
| Section rhsSection = ( Section )rhsManifest.sections.get( section.getName().toLowerCase() ); | |||
| if( !section.equals( rhsSection ) ) | |||
| { | |||
| return false; | |||
| } | |||
| } | |||
| return true; | |||
| } | |||
| /** | |||
| * Create or update the Manifest when used as a task. | |||
| * | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| if( manifestFile == null ) | |||
| { | |||
| throw new BuildException( "the file attribute is required" ); | |||
| } | |||
| Manifest toWrite = getDefaultManifest(); | |||
| if( mode.getValue().equals( "update" ) && manifestFile.exists() ) | |||
| { | |||
| FileReader f = null; | |||
| try | |||
| { | |||
| f = new FileReader( manifestFile ); | |||
| toWrite.merge( new Manifest( f ) ); | |||
| } | |||
| catch( ManifestException m ) | |||
| { | |||
| throw new BuildException( "Existing manifest " + manifestFile | |||
| + " is invalid", m, location ); | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| throw new BuildException( "Failed to read " + manifestFile, | |||
| e, location ); | |||
| } | |||
| finally | |||
| { | |||
| if( f != null ) | |||
| { | |||
| try | |||
| { | |||
| f.close(); | |||
| } | |||
| catch( IOException e ) | |||
| {} | |||
| } | |||
| } | |||
| } | |||
| try | |||
| { | |||
| toWrite.merge( this ); | |||
| } | |||
| catch( ManifestException m ) | |||
| { | |||
| throw new BuildException( "Manifest is invalid", m, location ); | |||
| } | |||
| PrintWriter w = null; | |||
| try | |||
| { | |||
| w = new PrintWriter( new FileWriter( manifestFile ) ); | |||
| toWrite.write( w ); | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| throw new BuildException( "Failed to write " + manifestFile, | |||
| e, location ); | |||
| } | |||
| finally | |||
| { | |||
| if( w != null ) | |||
| { | |||
| w.close(); | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Merge the contents of the given manifest into this manifest | |||
| * | |||
| * @param other the Manifest to be merged with this one. | |||
| * @throws ManifestException if there is a problem merging the manfest | |||
| * according to the Manifest spec. | |||
| */ | |||
| public void merge( Manifest other ) | |||
| throws ManifestException | |||
| { | |||
| if( other.manifestVersion != null ) | |||
| { | |||
| manifestVersion = other.manifestVersion; | |||
| } | |||
| mainSection.merge( other.mainSection ); | |||
| for( Enumeration e = other.sections.keys(); e.hasMoreElements(); ) | |||
| { | |||
| String sectionName = ( String )e.nextElement(); | |||
| Section ourSection = ( Section )sections.get( sectionName ); | |||
| Section otherSection = ( Section )other.sections.get( sectionName ); | |||
| if( ourSection == null ) | |||
| { | |||
| sections.put( sectionName.toLowerCase(), otherSection ); | |||
| } | |||
| else | |||
| { | |||
| ourSection.merge( otherSection ); | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Convert the manifest to its string representation | |||
| * | |||
| * @return a multiline string with the Manifest as it appears in a Manifest | |||
| * file. | |||
| */ | |||
| public String toString() | |||
| { | |||
| StringWriter sw = new StringWriter(); | |||
| try | |||
| { | |||
| write( new PrintWriter( sw ) ); | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| return null; | |||
| } | |||
| return sw.toString(); | |||
| } | |||
| /** | |||
| * Write the manifest out to a print writer. | |||
| * | |||
| * @param writer the Writer to which the manifest is written | |||
| * @throws IOException if the manifest cannot be written | |||
| */ | |||
| public void write( PrintWriter writer ) | |||
| throws IOException | |||
| { | |||
| writer.println( ATTRIBUTE_MANIFEST_VERSION + ": " + manifestVersion ); | |||
| String signatureVersion = mainSection.getAttributeValue( ATTRIBUTE_SIGNATURE_VERSION ); | |||
| if( signatureVersion != null ) | |||
| { | |||
| writer.println( ATTRIBUTE_SIGNATURE_VERSION + ": " + signatureVersion ); | |||
| mainSection.removeAttribute( ATTRIBUTE_SIGNATURE_VERSION ); | |||
| } | |||
| mainSection.write( writer ); | |||
| if( signatureVersion != null ) | |||
| { | |||
| try | |||
| { | |||
| mainSection.addConfiguredAttribute( new Attribute( ATTRIBUTE_SIGNATURE_VERSION, signatureVersion ) ); | |||
| } | |||
| catch( ManifestException e ) | |||
| { | |||
| // shouldn't happen - ignore | |||
| } | |||
| } | |||
| for( Enumeration e = sections.elements(); e.hasMoreElements(); ) | |||
| { | |||
| Section section = ( Section )e.nextElement(); | |||
| section.write( writer ); | |||
| } | |||
| } | |||
| /** | |||
| * Class to hold manifest attributes | |||
| * | |||
| * @author RT | |||
| */ | |||
| public static class Attribute | |||
| { | |||
| /** | |||
| * The attribute's name | |||
| */ | |||
| private String name = null; | |||
| /** | |||
| * The attribute's value | |||
| */ | |||
| private String value = null; | |||
| /** | |||
| * Construct an empty attribute | |||
| */ | |||
| public Attribute() { } | |||
| /** | |||
| * Construct an attribute by parsing a line from the Manifest | |||
| * | |||
| * @param line the line containing the attribute name and value | |||
| * @exception ManifestException Description of Exception | |||
| * @throws ManifestException if the line is not valid | |||
| */ | |||
| public Attribute( String line ) | |||
| throws ManifestException | |||
| { | |||
| parse( line ); | |||
| } | |||
| /** | |||
| * Construct a manifest by specifying its name and value | |||
| * | |||
| * @param name the attribute's name | |||
| * @param value the Attribute's value | |||
| */ | |||
| public Attribute( String name, String value ) | |||
| { | |||
| this.name = name; | |||
| this.value = value; | |||
| } | |||
| /** | |||
| * Set the Attribute's name | |||
| * | |||
| * @param name the attribute's name | |||
| */ | |||
| public void setName( String name ) | |||
| { | |||
| this.name = name; | |||
| } | |||
| /** | |||
| * Set the Attribute's value | |||
| * | |||
| * @param value the attribute's value | |||
| */ | |||
| public void setValue( String value ) | |||
| { | |||
| this.value = value; | |||
| } | |||
| /** | |||
| * Get the Attribute's name | |||
| * | |||
| * @return the attribute's name. | |||
| */ | |||
| public String getName() | |||
| { | |||
| return name; | |||
| } | |||
| /** | |||
| * Get the Attribute's value | |||
| * | |||
| * @return the attribute's value. | |||
| */ | |||
| public String getValue() | |||
| { | |||
| return value; | |||
| } | |||
| /** | |||
| * Add a continuation line from the Manifest file When lines are too | |||
| * long in a manifest, they are continued on the next line by starting | |||
| * with a space. This method adds the continuation data to the attribute | |||
| * value by skipping the first character. | |||
| * | |||
| * @param line The feature to be added to the Continuation attribute | |||
| */ | |||
| public void addContinuation( String line ) | |||
| { | |||
| value += line.substring( 1 ); | |||
| } | |||
| public boolean equals( Object rhs ) | |||
| { | |||
| if( !( rhs instanceof Attribute ) ) | |||
| { | |||
| return false; | |||
| } | |||
| Attribute rhsAttribute = ( Attribute )rhs; | |||
| return ( name != null && rhsAttribute.name != null && | |||
| name.toLowerCase().equals( rhsAttribute.name.toLowerCase() ) && | |||
| value != null && value.equals( rhsAttribute.value ) ); | |||
| } | |||
| /** | |||
| * Parse a line into name and value pairs | |||
| * | |||
| * @param line the line to be parsed | |||
| * @throws ManifestException if the line does not contain a colon | |||
| * separating the name and value | |||
| */ | |||
| public void parse( String line ) | |||
| throws ManifestException | |||
| { | |||
| int index = line.indexOf( ": " ); | |||
| if( index == -1 ) | |||
| { | |||
| throw new ManifestException( "Manifest line \"" + line + "\" is not valid as it does not " + | |||
| "contain a name and a value separated by ': ' " ); | |||
| } | |||
| name = line.substring( 0, index ); | |||
| value = line.substring( index + 2 ); | |||
| } | |||
| /** | |||
| * Write the attribute out to a print writer. | |||
| * | |||
| * @param writer the Writer to which the attribute is written | |||
| * @throws IOException if the attribte value cannot be written | |||
| */ | |||
| public void write( PrintWriter writer ) | |||
| throws IOException | |||
| { | |||
| String line = name + ": " + value; | |||
| while( line.getBytes().length > MAX_LINE_LENGTH ) | |||
| { | |||
| // try to find a MAX_LINE_LENGTH byte section | |||
| int breakIndex = MAX_LINE_LENGTH; | |||
| String section = line.substring( 0, breakIndex ); | |||
| while( section.getBytes().length > MAX_LINE_LENGTH && breakIndex > 0 ) | |||
| { | |||
| breakIndex--; | |||
| section = line.substring( 0, breakIndex ); | |||
| } | |||
| if( breakIndex == 0 ) | |||
| { | |||
| throw new IOException( "Unable to write manifest line " + name + ": " + value ); | |||
| } | |||
| writer.println( section ); | |||
| line = " " + line.substring( breakIndex ); | |||
| } | |||
| writer.println( line ); | |||
| } | |||
| } | |||
| /** | |||
| * Helper class for Manifest's mode attribute. | |||
| * | |||
| * @author RT | |||
| */ | |||
| public static class Mode extends EnumeratedAttribute | |||
| { | |||
| public String[] getValues() | |||
| { | |||
| return new String[]{"update", "replace"}; | |||
| } | |||
| } | |||
| /** | |||
| * Class to represent an individual section in the Manifest. A section | |||
| * consists of a set of attribute values, separated from other sections by a | |||
| * blank line. | |||
| * | |||
| * @author RT | |||
| */ | |||
| public static class Section | |||
| { | |||
| private Vector warnings = new Vector(); | |||
| /** | |||
| * The section's name if any. The main section in a manifest is unnamed. | |||
| */ | |||
| private String name = null; | |||
| /** | |||
| * The section's attributes. | |||
| */ | |||
| private Hashtable attributes = new Hashtable(); | |||
| /** | |||
| * Set the Section's name | |||
| * | |||
| * @param name the section's name | |||
| */ | |||
| public void setName( String name ) | |||
| { | |||
| this.name = name; | |||
| } | |||
| /** | |||
| * Get the value of the attribute with the name given. | |||
| * | |||
| * @param attributeName the name of the attribute to be returned. | |||
| * @return the attribute's value or null if the attribute does not exist | |||
| * in the section | |||
| */ | |||
| public String getAttributeValue( String attributeName ) | |||
| { | |||
| Object attribute = attributes.get( attributeName.toLowerCase() ); | |||
| if( attribute == null ) | |||
| { | |||
| return null; | |||
| } | |||
| if( attribute instanceof Attribute ) | |||
| { | |||
| return ( ( Attribute )attribute ).getValue(); | |||
| } | |||
| else | |||
| { | |||
| String value = ""; | |||
| for( Enumeration e = ( ( Vector )attribute ).elements(); e.hasMoreElements(); ) | |||
| { | |||
| Attribute classpathAttribute = ( Attribute )e.nextElement(); | |||
| value += classpathAttribute.getValue() + " "; | |||
| } | |||
| return value.trim(); | |||
| } | |||
| } | |||
| /** | |||
| * Get the Section's name | |||
| * | |||
| * @return the section's name. | |||
| */ | |||
| public String getName() | |||
| { | |||
| return name; | |||
| } | |||
| public Enumeration getWarnings() | |||
| { | |||
| return warnings.elements(); | |||
| } | |||
| /** | |||
| * Add an attribute to the section | |||
| * | |||
| * @param attribute the attribute to be added. | |||
| * @return the value of the attribute if it is a name attribute - null | |||
| * other wise | |||
| * @throws ManifestException if the attribute already exists in this | |||
| * section. | |||
| */ | |||
| public String addAttributeAndCheck( Attribute attribute ) | |||
| throws ManifestException | |||
| { | |||
| if( attribute.getName() == null || attribute.getValue() == null ) | |||
| { | |||
| throw new BuildException( "Attributes must have name and value" ); | |||
| } | |||
| if( attribute.getName().equalsIgnoreCase( ATTRIBUTE_NAME ) ) | |||
| { | |||
| warnings.addElement( "\"" + ATTRIBUTE_NAME + "\" attributes should not occur in the " + | |||
| "main section and must be the first element in all " + | |||
| "other sections: \"" + attribute.getName() + ": " + attribute.getValue() + "\"" ); | |||
| return attribute.getValue(); | |||
| } | |||
| if( attribute.getName().toLowerCase().startsWith( ATTRIBUTE_FROM.toLowerCase() ) ) | |||
| { | |||
| warnings.addElement( "Manifest attributes should not start with \"" + | |||
| ATTRIBUTE_FROM + "\" in \"" + attribute.getName() + ": " + attribute.getValue() + "\"" ); | |||
| } | |||
| else | |||
| { | |||
| // classpath attributes go into a vector | |||
| String attributeName = attribute.getName().toLowerCase(); | |||
| if( attributeName.equals( ATTRIBUTE_CLASSPATH ) ) | |||
| { | |||
| Vector classpathAttrs = ( Vector )attributes.get( attributeName ); | |||
| if( classpathAttrs == null ) | |||
| { | |||
| classpathAttrs = new Vector(); | |||
| attributes.put( attributeName, classpathAttrs ); | |||
| } | |||
| classpathAttrs.addElement( attribute ); | |||
| } | |||
| else if( attributes.containsKey( attributeName ) ) | |||
| { | |||
| throw new ManifestException( "The attribute \"" + attribute.getName() + "\" may not " + | |||
| "occur more than once in the same section" ); | |||
| } | |||
| else | |||
| { | |||
| attributes.put( attributeName, attribute ); | |||
| } | |||
| } | |||
| return null; | |||
| } | |||
| public void addConfiguredAttribute( Attribute attribute ) | |||
| throws ManifestException | |||
| { | |||
| String check = addAttributeAndCheck( attribute ); | |||
| if( check != null ) | |||
| { | |||
| throw new BuildException( "Specify the section name using the \"name\" attribute of the <section> element rather " + | |||
| "than using a \"Name\" manifest attribute" ); | |||
| } | |||
| } | |||
| public boolean equals( Object rhs ) | |||
| { | |||
| if( !( rhs instanceof Section ) ) | |||
| { | |||
| return false; | |||
| } | |||
| Section rhsSection = ( Section )rhs; | |||
| if( attributes.size() != rhsSection.attributes.size() ) | |||
| { | |||
| return false; | |||
| } | |||
| for( Enumeration e = attributes.elements(); e.hasMoreElements(); ) | |||
| { | |||
| Attribute attribute = ( Attribute )e.nextElement(); | |||
| Attribute rshAttribute = ( Attribute )rhsSection.attributes.get( attribute.getName().toLowerCase() ); | |||
| if( !attribute.equals( rshAttribute ) ) | |||
| { | |||
| return false; | |||
| } | |||
| } | |||
| return true; | |||
| } | |||
| /** | |||
| * Merge in another section | |||
| * | |||
| * @param section the section to be merged with this one. | |||
| * @throws ManifestException if the sections cannot be merged. | |||
| */ | |||
| public void merge( Section section ) | |||
| throws ManifestException | |||
| { | |||
| if( name == null && section.getName() != null || | |||
| name != null && !( name.equalsIgnoreCase( section.getName() ) ) ) | |||
| { | |||
| throw new ManifestException( "Unable to merge sections with different names" ); | |||
| } | |||
| for( Enumeration e = section.attributes.keys(); e.hasMoreElements(); ) | |||
| { | |||
| String attributeName = ( String )e.nextElement(); | |||
| if( attributeName.equals( ATTRIBUTE_CLASSPATH ) && | |||
| attributes.containsKey( attributeName ) ) | |||
| { | |||
| // classpath entries are vetors which are merged | |||
| Vector classpathAttrs = ( Vector )section.attributes.get( attributeName ); | |||
| Vector ourClasspathAttrs = ( Vector )attributes.get( attributeName ); | |||
| for( Enumeration e2 = classpathAttrs.elements(); e2.hasMoreElements(); ) | |||
| { | |||
| ourClasspathAttrs.addElement( e2.nextElement() ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| // the merge file always wins | |||
| attributes.put( attributeName, section.attributes.get( attributeName ) ); | |||
| } | |||
| } | |||
| // add in the warnings | |||
| for( Enumeration e = section.warnings.elements(); e.hasMoreElements(); ) | |||
| { | |||
| warnings.addElement( e.nextElement() ); | |||
| } | |||
| } | |||
| /** | |||
| * Read a section through a reader | |||
| * | |||
| * @param reader the reader from which the section is read | |||
| * @return the name of the next section if it has been read as part of | |||
| * this section - This only happens if the Manifest is malformed. | |||
| * @throws ManifestException if the section is not valid according to | |||
| * the JAR spec | |||
| * @throws IOException if the section cannot be read from the reader. | |||
| */ | |||
| public String read( BufferedReader reader ) | |||
| throws ManifestException, IOException | |||
| { | |||
| Attribute attribute = null; | |||
| while( true ) | |||
| { | |||
| String line = reader.readLine(); | |||
| if( line == null || line.length() == 0 ) | |||
| { | |||
| return null; | |||
| } | |||
| if( line.charAt( 0 ) == ' ' ) | |||
| { | |||
| // continuation line | |||
| if( attribute == null ) | |||
| { | |||
| if( name != null ) | |||
| { | |||
| // a continuation on the first line is a continuation of the name - concatenate | |||
| // this line and the name | |||
| name += line.substring( 1 ); | |||
| } | |||
| else | |||
| { | |||
| throw new ManifestException( "Can't start an attribute with a continuation line " + line ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| attribute.addContinuation( line ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| attribute = new Attribute( line ); | |||
| String nameReadAhead = addAttributeAndCheck( attribute ); | |||
| if( nameReadAhead != null ) | |||
| { | |||
| return nameReadAhead; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Remove tge given attribute from the section | |||
| * | |||
| * @param attributeName the name of the attribute to be removed. | |||
| */ | |||
| public void removeAttribute( String attributeName ) | |||
| { | |||
| attributes.remove( attributeName.toLowerCase() ); | |||
| } | |||
| /** | |||
| * Write the section out to a print writer. | |||
| * | |||
| * @param writer the Writer to which the section is written | |||
| * @throws IOException if the section cannot be written | |||
| */ | |||
| public void write( PrintWriter writer ) | |||
| throws IOException | |||
| { | |||
| if( name != null ) | |||
| { | |||
| Attribute nameAttr = new Attribute( ATTRIBUTE_NAME, name ); | |||
| nameAttr.write( writer ); | |||
| } | |||
| for( Enumeration e = attributes.elements(); e.hasMoreElements(); ) | |||
| { | |||
| Object object = e.nextElement(); | |||
| if( object instanceof Attribute ) | |||
| { | |||
| Attribute attribute = ( Attribute )object; | |||
| attribute.write( writer ); | |||
| } | |||
| else | |||
| { | |||
| Vector attrList = ( Vector )object; | |||
| for( Enumeration e2 = attrList.elements(); e2.hasMoreElements(); ) | |||
| { | |||
| Attribute attribute = ( Attribute )e2.nextElement(); | |||
| attribute.write( writer ); | |||
| } | |||
| } | |||
| } | |||
| writer.println(); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,29 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| /** | |||
| * Exception thrown indicating problems in a JAR Manifest | |||
| * | |||
| * @author <a href="mailto:conor@apache.org">Conor MacNeill</a> | |||
| */ | |||
| public class ManifestException extends Exception | |||
| { | |||
| /** | |||
| * Constructs an exception with the given descriptive message. | |||
| * | |||
| * @param msg Description of or information about the exception. | |||
| */ | |||
| public ManifestException( String msg ) | |||
| { | |||
| super( msg ); | |||
| } | |||
| } | |||
| @@ -0,0 +1,207 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.File; | |||
| import java.util.StringTokenizer; | |||
| import java.util.Vector; | |||
| import org.apache.tools.ant.DirectoryScanner; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.Task; | |||
| import org.apache.tools.ant.types.FileSet; | |||
| import org.apache.tools.ant.types.PatternSet; | |||
| /** | |||
| * This is an abstract task that should be used by all those tasks that require | |||
| * to include or exclude files based on pattern matching. | |||
| * | |||
| * @author Arnout J. Kuiper <a href="mailto:ajkuiper@wxs.nl">ajkuiper@wxs.nl</a> | |||
| * @author Stefano Mazzocchi <a href="mailto:stefano@apache.org"> | |||
| * stefano@apache.org</a> | |||
| * @author Sam Ruby <a href="mailto:rubys@us.ibm.com">rubys@us.ibm.com</a> | |||
| * @author Jon S. Stevens <a href="mailto:jon@clearink.com">jon@clearink.com</a> | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| */ | |||
| public abstract class MatchingTask extends Task | |||
| { | |||
| protected boolean useDefaultExcludes = true; | |||
| protected FileSet fileset = new FileSet(); | |||
| /** | |||
| * Sets whether default exclusions should be used or not. | |||
| * | |||
| * @param useDefaultExcludes "true"|"on"|"yes" when default exclusions | |||
| * should be used, "false"|"off"|"no" when they shouldn't be used. | |||
| */ | |||
| public void setDefaultexcludes( boolean useDefaultExcludes ) | |||
| { | |||
| this.useDefaultExcludes = useDefaultExcludes; | |||
| } | |||
| /** | |||
| * Sets the set of exclude patterns. Patterns may be separated by a comma or | |||
| * a space. | |||
| * | |||
| * @param excludes the string containing the exclude patterns | |||
| */ | |||
| public void setExcludes( String excludes ) | |||
| { | |||
| fileset.setExcludes( excludes ); | |||
| } | |||
| /** | |||
| * Sets the name of the file containing the includes patterns. | |||
| * | |||
| * @param excludesfile A string containing the filename to fetch the include | |||
| * patterns from. | |||
| */ | |||
| public void setExcludesfile( File excludesfile ) | |||
| { | |||
| fileset.setExcludesfile( excludesfile ); | |||
| } | |||
| /** | |||
| * Sets the set of include patterns. Patterns may be separated by a comma or | |||
| * a space. | |||
| * | |||
| * @param includes the string containing the include patterns | |||
| */ | |||
| public void setIncludes( String includes ) | |||
| { | |||
| fileset.setIncludes( includes ); | |||
| } | |||
| /** | |||
| * Sets the name of the file containing the includes patterns. | |||
| * | |||
| * @param includesfile A string containing the filename to fetch the include | |||
| * patterns from. | |||
| */ | |||
| public void setIncludesfile( File includesfile ) | |||
| { | |||
| fileset.setIncludesfile( includesfile ); | |||
| } | |||
| /** | |||
| * List of filenames and directory names to not include. They should be | |||
| * either , or " " (space) separated. The ignored files will be logged. | |||
| * | |||
| * @param ignoreString the string containing the files to ignore. | |||
| */ | |||
| public void XsetIgnore( String ignoreString ) | |||
| { | |||
| log( "The ignore attribute is deprecated." + | |||
| "Please use the excludes attribute.", | |||
| Project.MSG_WARN ); | |||
| if( ignoreString != null && ignoreString.length() > 0 ) | |||
| { | |||
| Vector tmpExcludes = new Vector(); | |||
| StringTokenizer tok = new StringTokenizer( ignoreString, ", ", false ); | |||
| while( tok.hasMoreTokens() ) | |||
| { | |||
| createExclude().setName( "**/" + tok.nextToken().trim() + "/**" ); | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Set this to be the items in the base directory that you want to be | |||
| * included. You can also specify "*" for the items (ie: items="*") and it | |||
| * will include all the items in the base directory. | |||
| * | |||
| * @param itemString the string containing the files to include. | |||
| */ | |||
| public void XsetItems( String itemString ) | |||
| { | |||
| log( "The items attribute is deprecated. " + | |||
| "Please use the includes attribute.", | |||
| Project.MSG_WARN ); | |||
| if( itemString == null || itemString.equals( "*" ) | |||
| || itemString.equals( "." ) ) | |||
| { | |||
| createInclude().setName( "**" ); | |||
| } | |||
| else | |||
| { | |||
| StringTokenizer tok = new StringTokenizer( itemString, ", " ); | |||
| while( tok.hasMoreTokens() ) | |||
| { | |||
| String pattern = tok.nextToken().trim(); | |||
| if( pattern.length() > 0 ) | |||
| { | |||
| createInclude().setName( pattern + "/**" ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * add a name entry on the exclude list | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public PatternSet.NameEntry createExclude() | |||
| { | |||
| return fileset.createExclude(); | |||
| } | |||
| /** | |||
| * add a name entry on the include files list | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public PatternSet.NameEntry createExcludesFile() | |||
| { | |||
| return fileset.createExcludesFile(); | |||
| } | |||
| /** | |||
| * add a name entry on the include list | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public PatternSet.NameEntry createInclude() | |||
| { | |||
| return fileset.createInclude(); | |||
| } | |||
| /** | |||
| * add a name entry on the include files list | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public PatternSet.NameEntry createIncludesFile() | |||
| { | |||
| return fileset.createIncludesFile(); | |||
| } | |||
| /** | |||
| * add a set of patterns | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public PatternSet createPatternSet() | |||
| { | |||
| return fileset.createPatternSet(); | |||
| } | |||
| /** | |||
| * Returns the directory scanner needed to access the files to process. | |||
| * | |||
| * @param baseDir Description of Parameter | |||
| * @return The DirectoryScanner value | |||
| */ | |||
| protected DirectoryScanner getDirectoryScanner( File baseDir ) | |||
| { | |||
| fileset.setDir( baseDir ); | |||
| fileset.setDefaultexcludes( useDefaultExcludes ); | |||
| return fileset.getDirectoryScanner( project ); | |||
| } | |||
| } | |||
| @@ -0,0 +1,55 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.File; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Task; | |||
| /** | |||
| * Creates a given directory. | |||
| * | |||
| * @author duncan@x180.com | |||
| */ | |||
| public class Mkdir extends Task | |||
| { | |||
| private File dir; | |||
| public void setDir( File dir ) | |||
| { | |||
| this.dir = dir; | |||
| } | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| if( dir == null ) | |||
| { | |||
| throw new BuildException( "dir attribute is required", location ); | |||
| } | |||
| if( dir.isFile() ) | |||
| { | |||
| throw new BuildException( "Unable to create directory as a file already exists with that name: " + dir.getAbsolutePath() ); | |||
| } | |||
| if( !dir.exists() ) | |||
| { | |||
| boolean result = dir.mkdirs(); | |||
| if( result == false ) | |||
| { | |||
| String msg = "Directory " + dir.getAbsolutePath() + " creation was not " + | |||
| "successful for an unknown reason"; | |||
| throw new BuildException( msg, location ); | |||
| } | |||
| log( "Created dir: " + dir.getAbsolutePath() ); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,302 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| import java.util.Enumeration; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.types.FileSet; | |||
| import org.apache.tools.ant.types.FilterSet; | |||
| import org.apache.tools.ant.types.FilterSetCollection; | |||
| /** | |||
| * Moves a file or directory to a new file or directory. By default, the | |||
| * destination is overwriten when existing. When overwrite is turned off, then | |||
| * files are only moved if the source file is newer than the destination file, | |||
| * or when the destination file does not exist.</p> <p> | |||
| * | |||
| * Source files and directories are only deleted when the file or directory has | |||
| * been copied to the destination successfully. Filtering also works.</p> <p> | |||
| * | |||
| * This implementation is based on Arnout Kuiper's initial design document, the | |||
| * following mailing list discussions, and the copyfile/copydir tasks.</p> | |||
| * | |||
| * @author Glenn McAllister <a href="mailto:glennm@ca.ibm.com">glennm@ca.ibm.com | |||
| * </a> | |||
| * @author <a href="mailto:umagesh@rediffmail.com">Magesh Umasankar</a> | |||
| */ | |||
| public class Move extends Copy | |||
| { | |||
| public Move() | |||
| { | |||
| super(); | |||
| forceOverwrite = true; | |||
| } | |||
| /** | |||
| * Go and delete the directory tree. | |||
| * | |||
| * @param d Description of Parameter | |||
| */ | |||
| protected void deleteDir( File d ) | |||
| { | |||
| String[] list = d.list(); | |||
| if( list == null ) | |||
| return;// on an io error list() can return null | |||
| for( int i = 0; i < list.length; i++ ) | |||
| { | |||
| String s = list[i]; | |||
| File f = new File( d, s ); | |||
| if( f.isDirectory() ) | |||
| { | |||
| deleteDir( f ); | |||
| } | |||
| else | |||
| { | |||
| throw new BuildException( "UNEXPECTED ERROR - The file " + f.getAbsolutePath() + " should not exist!" ); | |||
| } | |||
| } | |||
| log( "Deleting directory " + d.getAbsolutePath(), verbosity ); | |||
| if( !d.delete() ) | |||
| { | |||
| throw new BuildException( "Unable to delete directory " + d.getAbsolutePath() ); | |||
| } | |||
| } | |||
| //************************************************************************ | |||
| // protected and private methods | |||
| //************************************************************************ | |||
| protected void doFileOperations() | |||
| { | |||
| //Attempt complete directory renames, if any, first. | |||
| if( completeDirMap.size() > 0 ) | |||
| { | |||
| Enumeration e = completeDirMap.keys(); | |||
| while( e.hasMoreElements() ) | |||
| { | |||
| File fromDir = ( File )e.nextElement(); | |||
| File toDir = ( File )completeDirMap.get( fromDir ); | |||
| try | |||
| { | |||
| log( "Attempting to rename dir: " + fromDir + | |||
| " to " + toDir, verbosity ); | |||
| renameFile( fromDir, toDir, filtering, forceOverwrite ); | |||
| } | |||
| catch( IOException ioe ) | |||
| { | |||
| String msg = "Failed to rename dir " + fromDir | |||
| + " to " + toDir | |||
| + " due to " + ioe.getMessage(); | |||
| throw new BuildException( msg, ioe, location ); | |||
| } | |||
| } | |||
| } | |||
| if( fileCopyMap.size() > 0 ) | |||
| {// files to move | |||
| log( "Moving " + fileCopyMap.size() + " files to " + | |||
| destDir.getAbsolutePath() ); | |||
| Enumeration e = fileCopyMap.keys(); | |||
| while( e.hasMoreElements() ) | |||
| { | |||
| String fromFile = ( String )e.nextElement(); | |||
| String toFile = ( String )fileCopyMap.get( fromFile ); | |||
| if( fromFile.equals( toFile ) ) | |||
| { | |||
| log( "Skipping self-move of " + fromFile, verbosity ); | |||
| continue; | |||
| } | |||
| boolean moved = false; | |||
| File f = new File( fromFile ); | |||
| if( f.exists() ) | |||
| {//Is this file still available to be moved? | |||
| File d = new File( toFile ); | |||
| try | |||
| { | |||
| log( "Attempting to rename: " + fromFile + | |||
| " to " + toFile, verbosity ); | |||
| moved = renameFile( f, d, filtering, forceOverwrite ); | |||
| } | |||
| catch( IOException ioe ) | |||
| { | |||
| String msg = "Failed to rename " + fromFile | |||
| + " to " + toFile | |||
| + " due to " + ioe.getMessage(); | |||
| throw new BuildException( msg, ioe, location ); | |||
| } | |||
| if( !moved ) | |||
| { | |||
| try | |||
| { | |||
| log( "Moving " + fromFile + " to " + toFile, verbosity ); | |||
| FilterSetCollection executionFilters = new FilterSetCollection(); | |||
| if( filtering ) | |||
| { | |||
| executionFilters.addFilterSet( project.getGlobalFilterSet() ); | |||
| } | |||
| for( Enumeration filterEnum = getFilterSets().elements(); filterEnum.hasMoreElements(); ) | |||
| { | |||
| executionFilters.addFilterSet( ( FilterSet )filterEnum.nextElement() ); | |||
| } | |||
| getFileUtils().copyFile( f, d, executionFilters, | |||
| forceOverwrite ); | |||
| f = new File( fromFile ); | |||
| if( !f.delete() ) | |||
| { | |||
| throw new BuildException( "Unable to delete file " | |||
| + f.getAbsolutePath() ); | |||
| } | |||
| } | |||
| catch( IOException ioe ) | |||
| { | |||
| String msg = "Failed to copy " + fromFile + " to " | |||
| + toFile | |||
| + " due to " + ioe.getMessage(); | |||
| throw new BuildException( msg, ioe, location ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| if( includeEmpty ) | |||
| { | |||
| Enumeration e = dirCopyMap.elements(); | |||
| int count = 0; | |||
| while( e.hasMoreElements() ) | |||
| { | |||
| File d = new File( ( String )e.nextElement() ); | |||
| if( !d.exists() ) | |||
| { | |||
| if( !d.mkdirs() ) | |||
| { | |||
| log( "Unable to create directory " + d.getAbsolutePath(), Project.MSG_ERR ); | |||
| } | |||
| else | |||
| { | |||
| count++; | |||
| } | |||
| } | |||
| } | |||
| if( count > 0 ) | |||
| { | |||
| log( "Moved " + count + " empty directories to " + destDir.getAbsolutePath() ); | |||
| } | |||
| } | |||
| if( filesets.size() > 0 ) | |||
| { | |||
| Enumeration e = filesets.elements(); | |||
| while( e.hasMoreElements() ) | |||
| { | |||
| FileSet fs = ( FileSet )e.nextElement(); | |||
| File dir = fs.getDir( project ); | |||
| if( okToDelete( dir ) ) | |||
| { | |||
| deleteDir( dir ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Its only ok to delete a directory tree if there are no files in it. | |||
| * | |||
| * @param d Description of Parameter | |||
| * @return Description of the Returned Value | |||
| */ | |||
| protected boolean okToDelete( File d ) | |||
| { | |||
| String[] list = d.list(); | |||
| if( list == null ) | |||
| return false;// maybe io error? | |||
| for( int i = 0; i < list.length; i++ ) | |||
| { | |||
| String s = list[i]; | |||
| File f = new File( d, s ); | |||
| if( f.isDirectory() ) | |||
| { | |||
| if( !okToDelete( f ) ) | |||
| return false; | |||
| } | |||
| else | |||
| { | |||
| return false;// found a file | |||
| } | |||
| } | |||
| return true; | |||
| } | |||
| /** | |||
| * Attempts to rename a file from a source to a destination. If overwrite is | |||
| * set to true, this method overwrites existing file even if the destination | |||
| * file is newer. Otherwise, the source file is renamed only if the | |||
| * destination file is older than it. Method then checks if token filtering | |||
| * is used. If it is, this method returns false assuming it is the | |||
| * responsibility to the copyFile method. | |||
| * | |||
| * @param sourceFile Description of Parameter | |||
| * @param destFile Description of Parameter | |||
| * @param filtering Description of Parameter | |||
| * @param overwrite Description of Parameter | |||
| * @return Description of the Returned Value | |||
| * @exception BuildException Description of Exception | |||
| * @throws IOException | |||
| */ | |||
| protected boolean renameFile( File sourceFile, File destFile, | |||
| boolean filtering, boolean overwrite ) | |||
| throws IOException, BuildException | |||
| { | |||
| boolean renamed = true; | |||
| if( !filtering ) | |||
| { | |||
| // ensure that parent dir of dest file exists! | |||
| // not using getParentFile method to stay 1.1 compat | |||
| String parentPath = destFile.getParent(); | |||
| if( parentPath != null ) | |||
| { | |||
| File parent = new File( parentPath ); | |||
| if( !parent.exists() ) | |||
| { | |||
| parent.mkdirs(); | |||
| } | |||
| } | |||
| if( destFile.exists() ) | |||
| { | |||
| if( !destFile.delete() ) | |||
| { | |||
| throw new BuildException( "Unable to remove existing file " | |||
| + destFile ); | |||
| } | |||
| } | |||
| renamed = sourceFile.renameTo( destFile ); | |||
| } | |||
| else | |||
| { | |||
| renamed = false; | |||
| } | |||
| return renamed; | |||
| } | |||
| } | |||
| @@ -0,0 +1,93 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.File; | |||
| import java.io.FileInputStream; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.io.OutputStream; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Task; | |||
| /** | |||
| * Abstract Base class for pack tasks. | |||
| * | |||
| * @author <a href="mailto:umagesh@rediffmail.com">Magesh Umasankar</a> | |||
| */ | |||
| public abstract class Pack extends Task | |||
| { | |||
| protected File source; | |||
| protected File zipFile; | |||
| public void setSrc( File src ) | |||
| { | |||
| source = src; | |||
| } | |||
| public void setZipfile( File zipFile ) | |||
| { | |||
| this.zipFile = zipFile; | |||
| } | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| validate(); | |||
| log( "Building: " + zipFile.getAbsolutePath() ); | |||
| pack(); | |||
| } | |||
| protected abstract void pack(); | |||
| protected void zipFile( File file, OutputStream zOut ) | |||
| throws IOException | |||
| { | |||
| FileInputStream fIn = new FileInputStream( file ); | |||
| try | |||
| { | |||
| zipFile( fIn, zOut ); | |||
| } | |||
| finally | |||
| { | |||
| fIn.close(); | |||
| } | |||
| } | |||
| private void validate() | |||
| { | |||
| if( zipFile == null ) | |||
| { | |||
| throw new BuildException( "zipfile attribute is required", location ); | |||
| } | |||
| if( source == null ) | |||
| { | |||
| throw new BuildException( "src attribute is required", location ); | |||
| } | |||
| if( source.isDirectory() ) | |||
| { | |||
| throw new BuildException( "Src attribute must not " + | |||
| "represent a directory!", location ); | |||
| } | |||
| } | |||
| private void zipFile( InputStream in, OutputStream zOut ) | |||
| throws IOException | |||
| { | |||
| byte[] buffer = new byte[8 * 1024]; | |||
| int count = 0; | |||
| do | |||
| { | |||
| zOut.write( buffer, 0, count ); | |||
| count = in.read( buffer, 0, buffer.length ); | |||
| }while ( count != -1 ); | |||
| } | |||
| } | |||
| @@ -0,0 +1,170 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.util.Enumeration; | |||
| import java.util.Vector; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Location; | |||
| import org.apache.tools.ant.Task; | |||
| import org.apache.tools.ant.TaskContainer; | |||
| /** | |||
| * Implements a multi threaded task execution. <p> | |||
| * | |||
| * | |||
| * | |||
| * @author Thomas Christen <a href="mailto:chr@active.ch">chr@active.ch</a> | |||
| * @author <a href="mailto:conor@apache.org">Conor MacNeill </a> | |||
| */ | |||
| public class Parallel extends Task | |||
| implements TaskContainer | |||
| { | |||
| /** | |||
| * Collection holding the nested tasks | |||
| */ | |||
| private Vector nestedTasks = new Vector(); | |||
| /** | |||
| * Add a nested task to execute parallel (asynchron). <p> | |||
| * | |||
| * | |||
| * | |||
| * @param nestedTask Nested task to be executed in parallel | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| public void addTask( Task nestedTask ) | |||
| throws BuildException | |||
| { | |||
| nestedTasks.addElement( nestedTask ); | |||
| } | |||
| /** | |||
| * Block execution until the specified time or for a specified amount of | |||
| * milliseconds and if defined, execute the wait status. | |||
| * | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| TaskThread[] threads = new TaskThread[nestedTasks.size()]; | |||
| int threadNumber = 0; | |||
| for( Enumeration e = nestedTasks.elements(); e.hasMoreElements(); threadNumber++ ) | |||
| { | |||
| Task nestedTask = ( Task )e.nextElement(); | |||
| threads[threadNumber] = new TaskThread( threadNumber, nestedTask ); | |||
| } | |||
| // now start all threads | |||
| for( int i = 0; i < threads.length; ++i ) | |||
| { | |||
| threads[i].start(); | |||
| } | |||
| // now join to all the threads | |||
| for( int i = 0; i < threads.length; ++i ) | |||
| { | |||
| try | |||
| { | |||
| threads[i].join(); | |||
| } | |||
| catch( InterruptedException ie ) | |||
| { | |||
| // who would interrupt me at a time like this? | |||
| } | |||
| } | |||
| // now did any of the threads throw an exception | |||
| StringBuffer exceptionMessage = new StringBuffer(); | |||
| String lSep = System.getProperty( "line.separator" ); | |||
| int numExceptions = 0; | |||
| Throwable firstException = null; | |||
| Location firstLocation = Location.UNKNOWN_LOCATION; | |||
| ; | |||
| for( int i = 0; i < threads.length; ++i ) | |||
| { | |||
| Throwable t = threads[i].getException(); | |||
| if( t != null ) | |||
| { | |||
| numExceptions++; | |||
| if( firstException == null ) | |||
| { | |||
| firstException = t; | |||
| } | |||
| if( t instanceof BuildException && | |||
| firstLocation == Location.UNKNOWN_LOCATION ) | |||
| { | |||
| firstLocation = ( ( BuildException )t ).getLocation(); | |||
| } | |||
| exceptionMessage.append( lSep ); | |||
| exceptionMessage.append( t.getMessage() ); | |||
| } | |||
| } | |||
| if( numExceptions == 1 ) | |||
| { | |||
| if( firstException instanceof BuildException ) | |||
| { | |||
| throw ( BuildException )firstException; | |||
| } | |||
| else | |||
| { | |||
| throw new BuildException( firstException ); | |||
| } | |||
| } | |||
| else if( numExceptions > 1 ) | |||
| { | |||
| throw new BuildException( exceptionMessage.toString(), firstLocation ); | |||
| } | |||
| } | |||
| class TaskThread extends Thread | |||
| { | |||
| private Throwable exception; | |||
| private Task task; | |||
| private int taskNumber; | |||
| /** | |||
| * Construct a new TaskThread<p> | |||
| * | |||
| * | |||
| * | |||
| * @param task the Task to be executed in a seperate thread | |||
| * @param taskNumber Description of Parameter | |||
| */ | |||
| TaskThread( int taskNumber, Task task ) | |||
| { | |||
| this.task = task; | |||
| this.taskNumber = taskNumber; | |||
| } | |||
| public Throwable getException() | |||
| { | |||
| return exception; | |||
| } | |||
| /** | |||
| * Executes the task within a thread and takes care about Exceptions | |||
| * raised within the task. | |||
| */ | |||
| public void run() | |||
| { | |||
| try | |||
| { | |||
| task.perform(); | |||
| } | |||
| catch( Throwable t ) | |||
| { | |||
| exception = t; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,157 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.Task; | |||
| import org.apache.tools.ant.types.Commandline; | |||
| /** | |||
| * Task as a layer on top of patch. Patch applies a diff file to an original. | |||
| * | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| */ | |||
| public class Patch extends Task | |||
| { | |||
| private boolean havePatchfile = false; | |||
| private Commandline cmd = new Commandline(); | |||
| private File originalFile; | |||
| /** | |||
| * Shall patch write backups. | |||
| * | |||
| * @param backups The new Backups value | |||
| */ | |||
| public void setBackups( boolean backups ) | |||
| { | |||
| if( backups ) | |||
| { | |||
| cmd.createArgument().setValue( "-b" ); | |||
| } | |||
| } | |||
| /** | |||
| * Ignore whitespace differences. | |||
| * | |||
| * @param ignore The new Ignorewhitespace value | |||
| */ | |||
| public void setIgnorewhitespace( boolean ignore ) | |||
| { | |||
| if( ignore ) | |||
| { | |||
| cmd.createArgument().setValue( "-l" ); | |||
| } | |||
| } | |||
| /** | |||
| * The file to patch. | |||
| * | |||
| * @param file The new Originalfile value | |||
| */ | |||
| public void setOriginalfile( File file ) | |||
| { | |||
| originalFile = file; | |||
| } | |||
| /** | |||
| * The file containing the diff output. | |||
| * | |||
| * @param file The new Patchfile value | |||
| */ | |||
| public void setPatchfile( File file ) | |||
| { | |||
| if( !file.exists() ) | |||
| { | |||
| throw new BuildException( "patchfile " + file + " doesn\'t exist", | |||
| location ); | |||
| } | |||
| cmd.createArgument().setValue( "-i" ); | |||
| cmd.createArgument().setFile( file ); | |||
| havePatchfile = true; | |||
| } | |||
| /** | |||
| * Work silently unless an error occurs. | |||
| * | |||
| * @param q The new Quiet value | |||
| */ | |||
| public void setQuiet( boolean q ) | |||
| { | |||
| if( q ) | |||
| { | |||
| cmd.createArgument().setValue( "-s" ); | |||
| } | |||
| } | |||
| /** | |||
| * Assume patch was created with old and new files swapped. | |||
| * | |||
| * @param r The new Reverse value | |||
| */ | |||
| public void setReverse( boolean r ) | |||
| { | |||
| if( r ) | |||
| { | |||
| cmd.createArgument().setValue( "-R" ); | |||
| } | |||
| } | |||
| /** | |||
| * Strip the smallest prefix containing <i>num</i> leading slashes from | |||
| * filenames. <p> | |||
| * | |||
| * patch's <i>-p</i> option. | |||
| * | |||
| * @param num The new Strip value | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| public void setStrip( int num ) | |||
| throws BuildException | |||
| { | |||
| if( num < 0 ) | |||
| { | |||
| throw new BuildException( "strip has to be >= 0", location ); | |||
| } | |||
| cmd.createArgument().setValue( "-p" + num ); | |||
| } | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| if( !havePatchfile ) | |||
| { | |||
| throw new BuildException( "patchfile argument is required", | |||
| location ); | |||
| } | |||
| Commandline toExecute = ( Commandline )cmd.clone(); | |||
| toExecute.setExecutable( "patch" ); | |||
| if( originalFile != null ) | |||
| { | |||
| toExecute.createArgument().setFile( originalFile ); | |||
| } | |||
| Execute exe = new Execute( new LogStreamHandler( this, Project.MSG_INFO, | |||
| Project.MSG_WARN ), | |||
| null ); | |||
| exe.setCommandline( toExecute.getCommandline() ); | |||
| try | |||
| { | |||
| exe.execute(); | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| throw new BuildException( e ); | |||
| } | |||
| } | |||
| }// Patch | |||
| @@ -0,0 +1,397 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.File; | |||
| import java.util.Vector; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.Task; | |||
| import org.apache.tools.ant.types.FileSet; | |||
| import org.apache.tools.ant.types.Path; | |||
| import org.apache.tools.ant.types.Reference; | |||
| /** | |||
| * This task converts path and classpath information to a specific target OS | |||
| * format. The resulting formatted path is placed into a specified property. <p> | |||
| * | |||
| * LIMITATION: Currently this implementation groups all machines into one of two | |||
| * types: Unix or Windows. Unix is defined as NOT windows. | |||
| * | |||
| * @author Larry Streepy <a href="mailto:streepy@healthlanguage.com"> | |||
| * streepy@healthlanguage.com</a> | |||
| */ | |||
| public class PathConvert extends Task | |||
| { | |||
| // Members | |||
| private Path path = null;// Path to be converted | |||
| private Reference refid = null;// Reference to path/fileset to convert | |||
| private String targetOS = null;// The target OS type | |||
| private boolean targetWindows = false;// Set when targetOS is set | |||
| private boolean onWindows = false;// Set if we're running on windows | |||
| private String property = null;// The property to receive the results | |||
| private Vector prefixMap = new Vector();// Path prefix map | |||
| private String pathSep = null;// User override on path sep char | |||
| private String dirSep = null; | |||
| /** | |||
| * Override the default directory separator string for the target os | |||
| * | |||
| * @param sep The new DirSep value | |||
| */ | |||
| public void setDirSep( String sep ) | |||
| { | |||
| dirSep = sep; | |||
| } | |||
| /** | |||
| * Override the default path separator string for the target os | |||
| * | |||
| * @param sep The new PathSep value | |||
| */ | |||
| public void setPathSep( String sep ) | |||
| { | |||
| pathSep = sep; | |||
| } | |||
| /** | |||
| * Set the value of the proprty attribute - this is the property into which | |||
| * our converted path will be placed. | |||
| * | |||
| * @param p The new Property value | |||
| */ | |||
| public void setProperty( String p ) | |||
| { | |||
| property = p; | |||
| } | |||
| /** | |||
| * Adds a reference to a PATH or FILESET defined elsewhere. | |||
| * | |||
| * @param r The new Refid value | |||
| */ | |||
| public void setRefid( Reference r ) | |||
| { | |||
| if( path != null ) | |||
| throw noChildrenAllowed(); | |||
| refid = r; | |||
| } | |||
| /** | |||
| * Set the value of the targetos attribute | |||
| * | |||
| * @param target The new Targetos value | |||
| */ | |||
| public void setTargetos( String target ) | |||
| { | |||
| targetOS = target.toLowerCase(); | |||
| if( !targetOS.equals( "windows" ) && !target.equals( "unix" ) && | |||
| !targetOS.equals( "netware" ) ) | |||
| { | |||
| throw new BuildException( "targetos must be one of 'unix', 'netware', or 'windows'" ); | |||
| } | |||
| // Currently, we deal with only two path formats: Unix and Windows | |||
| // And Unix is everything that is not Windows | |||
| // for NetWare, piggy-back on Windows, since in the validateSetup code, | |||
| // the same assumptions can be made as with windows - | |||
| // that ; is the path separator | |||
| targetWindows = ( targetOS.equals( "windows" ) || targetOS.equals( "netware" ) ); | |||
| } | |||
| /** | |||
| * Has the refid attribute of this element been set? | |||
| * | |||
| * @return The Reference value | |||
| */ | |||
| public boolean isReference() | |||
| { | |||
| return refid != null; | |||
| } | |||
| /** | |||
| * Create a nested MAP element | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public MapEntry createMap() | |||
| { | |||
| MapEntry entry = new MapEntry(); | |||
| prefixMap.addElement( entry ); | |||
| return entry; | |||
| } | |||
| /** | |||
| * Create a nested PATH element | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public Path createPath() | |||
| { | |||
| if( isReference() ) | |||
| throw noChildrenAllowed(); | |||
| if( path == null ) | |||
| { | |||
| path = new Path( getProject() ); | |||
| } | |||
| return path.createPath(); | |||
| } | |||
| /** | |||
| * Do the execution. | |||
| * | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| // If we are a reference, the create a Path from the reference | |||
| if( isReference() ) | |||
| { | |||
| path = new Path( getProject() ).createPath(); | |||
| Object obj = refid.getReferencedObject( getProject() ); | |||
| if( obj instanceof Path ) | |||
| { | |||
| path.setRefid( refid ); | |||
| } | |||
| else if( obj instanceof FileSet ) | |||
| { | |||
| FileSet fs = ( FileSet )obj; | |||
| path.addFileset( fs ); | |||
| } | |||
| else | |||
| { | |||
| throw new BuildException( "'refid' does not refer to a path or fileset" ); | |||
| } | |||
| } | |||
| validateSetup();// validate our setup | |||
| // Currently, we deal with only two path formats: Unix and Windows | |||
| // And Unix is everything that is not Windows | |||
| // (with the exception for NetWare below) | |||
| String osname = System.getProperty( "os.name" ).toLowerCase(); | |||
| // for NetWare, piggy-back on Windows, since here and in the | |||
| // apply code, the same assumptions can be made as with windows - | |||
| // that \\ is an OK separator, and do comparisons case-insensitive. | |||
| onWindows = ( ( osname.indexOf( "windows" ) >= 0 ) || | |||
| ( osname.indexOf( "netware" ) >= 0 ) ); | |||
| // Determine the from/to char mappings for dir sep | |||
| char fromDirSep = onWindows ? '\\' : '/'; | |||
| char toDirSep = dirSep.charAt( 0 ); | |||
| StringBuffer rslt = new StringBuffer( 100 ); | |||
| // Get the list of path components in canonical form | |||
| String[] elems = path.list(); | |||
| for( int i = 0; i < elems.length; i++ ) | |||
| { | |||
| String elem = elems[i]; | |||
| elem = mapElement( elem );// Apply the path prefix map | |||
| // Now convert the path and file separator characters from the | |||
| // current os to the target os. | |||
| elem = elem.replace( fromDirSep, toDirSep ); | |||
| if( i != 0 ) | |||
| rslt.append( pathSep ); | |||
| rslt.append( elem ); | |||
| } | |||
| // Place the result into the specified property | |||
| String value = rslt.toString(); | |||
| log( "Set property " + property + " = " + value, Project.MSG_VERBOSE ); | |||
| getProject().setNewProperty( property, value ); | |||
| } | |||
| /** | |||
| * Apply the configured map to a path element. The map is used to convert | |||
| * between Windows drive letters and Unix paths. If no map is configured, | |||
| * then the input string is returned unchanged. | |||
| * | |||
| * @param elem The path element to apply the map to | |||
| * @return String Updated element | |||
| */ | |||
| private String mapElement( String elem ) | |||
| { | |||
| int size = prefixMap.size(); | |||
| if( size != 0 ) | |||
| { | |||
| // Iterate over the map entries and apply each one. Stop when one of the | |||
| // entries actually changes the element | |||
| for( int i = 0; i < size; i++ ) | |||
| { | |||
| MapEntry entry = ( MapEntry )prefixMap.elementAt( i ); | |||
| String newElem = entry.apply( elem ); | |||
| // Note I'm using "!=" to see if we got a new object back from | |||
| // the apply method. | |||
| if( newElem != elem ) | |||
| { | |||
| elem = newElem; | |||
| break;// We applied one, so we're done | |||
| } | |||
| } | |||
| } | |||
| return elem; | |||
| } | |||
| /** | |||
| * Creates an exception that indicates that this XML element must not have | |||
| * child elements if the refid attribute is set. | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| private BuildException noChildrenAllowed() | |||
| { | |||
| return new BuildException( "You must not specify nested PATH elements when using refid" ); | |||
| } | |||
| /** | |||
| * Validate that all our parameters have been properly initialized. | |||
| * | |||
| * @throws BuildException if something is not setup properly | |||
| */ | |||
| private void validateSetup() | |||
| throws BuildException | |||
| { | |||
| if( path == null ) | |||
| throw new BuildException( "You must specify a path to convert" ); | |||
| if( property == null ) | |||
| throw new BuildException( "You must specify a property" ); | |||
| // Must either have a target OS or both a dirSep and pathSep | |||
| if( targetOS == null && pathSep == null && dirSep == null ) | |||
| throw new BuildException( "You must specify at least one of targetOS, dirSep, or pathSep" ); | |||
| // Determine the separator strings. The dirsep and pathsep attributes | |||
| // override the targetOS settings. | |||
| String dsep = File.separator; | |||
| String psep = File.pathSeparator; | |||
| if( targetOS != null ) | |||
| { | |||
| psep = targetWindows ? ";" : ":"; | |||
| dsep = targetWindows ? "\\" : "/"; | |||
| } | |||
| if( pathSep != null ) | |||
| {// override with pathsep= | |||
| psep = pathSep; | |||
| } | |||
| if( dirSep != null ) | |||
| {// override with dirsep= | |||
| dsep = dirSep; | |||
| } | |||
| pathSep = psep; | |||
| dirSep = dsep; | |||
| } | |||
| /** | |||
| * Helper class, holds the nested <map> values. Elements will look like | |||
| * this: <map from="d:" to="/foo"/> <p> | |||
| * | |||
| * When running on windows, the prefix comparison will be case insensitive. | |||
| * | |||
| * @author RT | |||
| */ | |||
| public class MapEntry | |||
| { | |||
| // Members | |||
| private String from = null; | |||
| private String to = null; | |||
| /** | |||
| * Set the "from" attribute of the map entry | |||
| * | |||
| * @param from The new From value | |||
| */ | |||
| public void setFrom( String from ) | |||
| { | |||
| this.from = from; | |||
| } | |||
| /** | |||
| * Set the "to" attribute of the map entry | |||
| * | |||
| * @param to The new To value | |||
| */ | |||
| public void setTo( String to ) | |||
| { | |||
| this.to = to; | |||
| } | |||
| /** | |||
| * Apply this map entry to a given path element | |||
| * | |||
| * @param elem Path element to process | |||
| * @return String Updated path element after mapping | |||
| */ | |||
| public String apply( String elem ) | |||
| { | |||
| if( from == null || to == null ) | |||
| { | |||
| throw new BuildException( "Both 'from' and 'to' must be set in a map entry" ); | |||
| } | |||
| // If we're on windows, then do the comparison ignoring case | |||
| String cmpElem = onWindows ? elem.toLowerCase() : elem; | |||
| String cmpFrom = onWindows ? from.toLowerCase() : from; | |||
| // If the element starts with the configured prefix, then convert the prefix | |||
| // to the configured 'to' value. | |||
| if( cmpElem.startsWith( cmpFrom ) ) | |||
| { | |||
| int len = from.length(); | |||
| if( len >= elem.length() ) | |||
| { | |||
| elem = to; | |||
| } | |||
| else | |||
| { | |||
| elem = to + elem.substring( len ); | |||
| } | |||
| } | |||
| return elem; | |||
| } | |||
| }// User override on directory sep char | |||
| } | |||
| @@ -0,0 +1,90 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.lang.reflect.Method; | |||
| import java.util.Enumeration; | |||
| import java.util.Vector; | |||
| /** | |||
| * Destroys all registered <code>Process</code>es when the VM exits. | |||
| * | |||
| * @author <a href="mailto:mnewcomb@tacintel.com">Michael Newcomb</a> | |||
| */ | |||
| class ProcessDestroyer | |||
| extends Thread | |||
| { | |||
| private Vector processes = new Vector(); | |||
| /** | |||
| * Constructs a <code>ProcessDestroyer</code> and registers it as a shutdown | |||
| * hook. | |||
| */ | |||
| public ProcessDestroyer() | |||
| { | |||
| try | |||
| { | |||
| // check to see if the method exists (support pre-JDK 1.3 VMs) | |||
| // | |||
| Class[] paramTypes = {Thread.class}; | |||
| Method addShutdownHook = | |||
| Runtime.class.getMethod( "addShutdownHook", paramTypes ); | |||
| // add the hook | |||
| // | |||
| Object[] args = {this}; | |||
| addShutdownHook.invoke( Runtime.getRuntime(), args ); | |||
| } | |||
| catch( Exception e ) | |||
| { | |||
| // it just won't be added as a shutdown hook... :( | |||
| } | |||
| } | |||
| /** | |||
| * Returns <code>true</code> if the specified <code>Process</code> was | |||
| * successfully added to the list of processes to destroy upon VM exit. | |||
| * | |||
| * @param process the process to add | |||
| * @return <code>true</code> if the specified <code>Process</code> was | |||
| * successfully added | |||
| */ | |||
| public boolean add( Process process ) | |||
| { | |||
| processes.addElement( process ); | |||
| return processes.contains( process ); | |||
| } | |||
| /** | |||
| * Returns <code>true</code> if the specified <code>Process</code> was | |||
| * successfully removed from the list of processes to destroy upon VM exit. | |||
| * | |||
| * @param process the process to remove | |||
| * @return <code>true</code> if the specified <code>Process</code> was | |||
| * successfully removed | |||
| */ | |||
| public boolean remove( Process process ) | |||
| { | |||
| return processes.removeElement( process ); | |||
| } | |||
| /** | |||
| * Invoked by the VM when it is exiting. | |||
| */ | |||
| public void run() | |||
| { | |||
| synchronized( processes ) | |||
| { | |||
| Enumeration e = processes.elements(); | |||
| while( e.hasMoreElements() ) | |||
| { | |||
| ( ( Process )e.nextElement() ).destroy(); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,394 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.File; | |||
| import java.io.FileInputStream; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.util.Enumeration; | |||
| import java.util.Properties; | |||
| import java.util.Vector; | |||
| import org.apache.tools.ant.AntClassLoader; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.ProjectHelper; | |||
| import org.apache.tools.ant.Task; | |||
| import org.apache.tools.ant.types.Path; | |||
| import org.apache.tools.ant.types.Reference; | |||
| /** | |||
| * Will set a Project property. Used to be a hack in ProjectHelper Will not | |||
| * override values set by the command line or parent projects. | |||
| * | |||
| * @author costin@dnt.ro | |||
| * @author <a href="mailto:rubys@us.ibm.com">Sam Ruby</a> | |||
| * @author <a href="mailto:glennm@ca.ibm.com">Glenn McAllister</a> | |||
| */ | |||
| public class Property extends Task | |||
| { | |||
| protected Path classpath; | |||
| protected String env; | |||
| protected File file; | |||
| protected String name; | |||
| protected Reference ref; | |||
| protected String resource; | |||
| protected boolean userProperty; | |||
| protected String value;// set read-only properties | |||
| public Property() | |||
| { | |||
| super(); | |||
| } | |||
| protected Property( boolean userProperty ) | |||
| { | |||
| this.userProperty = userProperty; | |||
| } | |||
| public void setClasspath( Path classpath ) | |||
| { | |||
| if( this.classpath == null ) | |||
| { | |||
| this.classpath = classpath; | |||
| } | |||
| else | |||
| { | |||
| this.classpath.append( classpath ); | |||
| } | |||
| } | |||
| public void setClasspathRef( Reference r ) | |||
| { | |||
| createClasspath().setRefid( r ); | |||
| } | |||
| public void setEnvironment( String env ) | |||
| { | |||
| this.env = env; | |||
| } | |||
| public void setFile( File file ) | |||
| { | |||
| this.file = file; | |||
| } | |||
| public void setLocation( File location ) | |||
| { | |||
| setValue( location.getAbsolutePath() ); | |||
| } | |||
| public void setName( String name ) | |||
| { | |||
| this.name = name; | |||
| } | |||
| public void setRefid( Reference ref ) | |||
| { | |||
| this.ref = ref; | |||
| } | |||
| public void setResource( String resource ) | |||
| { | |||
| this.resource = resource; | |||
| } | |||
| /** | |||
| * @param userProperty The new UserProperty value | |||
| * @deprecated This was never a supported feature and has been deprecated | |||
| * without replacement | |||
| */ | |||
| public void setUserProperty( boolean userProperty ) | |||
| { | |||
| log( "DEPRECATED: Ignoring request to set user property in Property task.", | |||
| Project.MSG_WARN ); | |||
| } | |||
| public void setValue( String value ) | |||
| { | |||
| this.value = value; | |||
| } | |||
| public String getEnvironment() | |||
| { | |||
| return env; | |||
| } | |||
| public File getFile() | |||
| { | |||
| return file; | |||
| } | |||
| public String getName() | |||
| { | |||
| return name; | |||
| } | |||
| public Reference getRefid() | |||
| { | |||
| return ref; | |||
| } | |||
| public String getResource() | |||
| { | |||
| return resource; | |||
| } | |||
| public String getValue() | |||
| { | |||
| return value; | |||
| } | |||
| public Path createClasspath() | |||
| { | |||
| if( this.classpath == null ) | |||
| { | |||
| this.classpath = new Path( project ); | |||
| } | |||
| return this.classpath.createPath(); | |||
| } | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| if( name != null ) | |||
| { | |||
| if( value == null && ref == null ) | |||
| { | |||
| throw new BuildException( "You must specify value, location or refid with the name attribute", | |||
| location ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| if( file == null && resource == null && env == null ) | |||
| { | |||
| throw new BuildException( "You must specify file, resource or environment when not using the name attribute", | |||
| location ); | |||
| } | |||
| } | |||
| if( ( name != null ) && ( value != null ) ) | |||
| { | |||
| addProperty( name, value ); | |||
| } | |||
| if( file != null ) | |||
| loadFile( file ); | |||
| if( resource != null ) | |||
| loadResource( resource ); | |||
| if( env != null ) | |||
| loadEnvironment( env ); | |||
| if( ( name != null ) && ( ref != null ) ) | |||
| { | |||
| Object obj = ref.getReferencedObject( getProject() ); | |||
| if( obj != null ) | |||
| { | |||
| addProperty( name, obj.toString() ); | |||
| } | |||
| } | |||
| } | |||
| public String toString() | |||
| { | |||
| return value == null ? "" : value; | |||
| } | |||
| protected void addProperties( Properties props ) | |||
| { | |||
| resolveAllProperties( props ); | |||
| Enumeration e = props.keys(); | |||
| while( e.hasMoreElements() ) | |||
| { | |||
| String name = ( String )e.nextElement(); | |||
| String value = ( String )props.getProperty( name ); | |||
| String v = project.replaceProperties( value ); | |||
| addProperty( name, v ); | |||
| } | |||
| } | |||
| protected void addProperty( String n, String v ) | |||
| { | |||
| if( userProperty ) | |||
| { | |||
| if( project.getUserProperty( n ) == null ) | |||
| { | |||
| project.setUserProperty( n, v ); | |||
| } | |||
| else | |||
| { | |||
| log( "Override ignored for " + n, Project.MSG_VERBOSE ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| project.setNewProperty( n, v ); | |||
| } | |||
| } | |||
| protected void loadEnvironment( String prefix ) | |||
| { | |||
| Properties props = new Properties(); | |||
| if( !prefix.endsWith( "." ) ) | |||
| prefix += "."; | |||
| log( "Loading Environment " + prefix, Project.MSG_VERBOSE ); | |||
| Vector osEnv = Execute.getProcEnvironment(); | |||
| for( Enumeration e = osEnv.elements(); e.hasMoreElements(); ) | |||
| { | |||
| String entry = ( String )e.nextElement(); | |||
| int pos = entry.indexOf( '=' ); | |||
| if( pos == -1 ) | |||
| { | |||
| log( "Ignoring: " + entry, Project.MSG_WARN ); | |||
| } | |||
| else | |||
| { | |||
| props.put( prefix + entry.substring( 0, pos ), | |||
| entry.substring( pos + 1 ) ); | |||
| } | |||
| } | |||
| addProperties( props ); | |||
| } | |||
| protected void loadFile( File file ) | |||
| throws BuildException | |||
| { | |||
| Properties props = new Properties(); | |||
| log( "Loading " + file.getAbsolutePath(), Project.MSG_VERBOSE ); | |||
| try | |||
| { | |||
| if( file.exists() ) | |||
| { | |||
| FileInputStream fis = new FileInputStream( file ); | |||
| try | |||
| { | |||
| props.load( fis ); | |||
| } | |||
| finally | |||
| { | |||
| if( fis != null ) | |||
| { | |||
| fis.close(); | |||
| } | |||
| } | |||
| addProperties( props ); | |||
| } | |||
| else | |||
| { | |||
| log( "Unable to find property file: " + file.getAbsolutePath(), | |||
| Project.MSG_VERBOSE ); | |||
| } | |||
| } | |||
| catch( IOException ex ) | |||
| { | |||
| throw new BuildException( ex ); | |||
| } | |||
| } | |||
| protected void loadResource( String name ) | |||
| { | |||
| Properties props = new Properties(); | |||
| log( "Resource Loading " + name, Project.MSG_VERBOSE ); | |||
| try | |||
| { | |||
| ClassLoader cL = null; | |||
| InputStream is = null; | |||
| if( classpath != null ) | |||
| { | |||
| cL = new AntClassLoader( project, classpath ); | |||
| } | |||
| else | |||
| { | |||
| cL = this.getClass().getClassLoader(); | |||
| } | |||
| if( cL == null ) | |||
| { | |||
| is = ClassLoader.getSystemResourceAsStream( name ); | |||
| } | |||
| else | |||
| { | |||
| is = cL.getResourceAsStream( name ); | |||
| } | |||
| if( is != null ) | |||
| { | |||
| props.load( is ); | |||
| addProperties( props ); | |||
| } | |||
| else | |||
| { | |||
| log( "Unable to find resource " + name, Project.MSG_WARN ); | |||
| } | |||
| } | |||
| catch( IOException ex ) | |||
| { | |||
| throw new BuildException( ex ); | |||
| } | |||
| } | |||
| private void resolveAllProperties( Properties props ) | |||
| throws BuildException | |||
| { | |||
| for( Enumeration e = props.keys(); e.hasMoreElements(); ) | |||
| { | |||
| String name = ( String )e.nextElement(); | |||
| String value = props.getProperty( name ); | |||
| boolean resolved = false; | |||
| while( !resolved ) | |||
| { | |||
| Vector fragments = new Vector(); | |||
| Vector propertyRefs = new Vector(); | |||
| ProjectHelper.parsePropertyString( value, fragments, propertyRefs ); | |||
| resolved = true; | |||
| if( propertyRefs.size() != 0 ) | |||
| { | |||
| StringBuffer sb = new StringBuffer(); | |||
| Enumeration i = fragments.elements(); | |||
| Enumeration j = propertyRefs.elements(); | |||
| while( i.hasMoreElements() ) | |||
| { | |||
| String fragment = ( String )i.nextElement(); | |||
| if( fragment == null ) | |||
| { | |||
| String propertyName = ( String )j.nextElement(); | |||
| if( propertyName.equals( name ) ) | |||
| { | |||
| throw new BuildException( "Property " + name + " was circularly defined." ); | |||
| } | |||
| fragment = getProject().getProperty( propertyName ); | |||
| if( fragment == null ) | |||
| { | |||
| if( props.containsKey( propertyName ) ) | |||
| { | |||
| fragment = props.getProperty( propertyName ); | |||
| resolved = false; | |||
| } | |||
| else | |||
| { | |||
| fragment = "${" + propertyName + "}"; | |||
| } | |||
| } | |||
| } | |||
| sb.append( fragment ); | |||
| } | |||
| value = sb.toString(); | |||
| props.put( name, value ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,130 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.io.OutputStream; | |||
| /** | |||
| * Copies standard output and error of subprocesses to standard output and error | |||
| * of the parent process. TODO: standard input of the subprocess is not | |||
| * implemented. | |||
| * | |||
| * @author thomas.haas@softwired-inc.com | |||
| */ | |||
| public class PumpStreamHandler implements ExecuteStreamHandler | |||
| { | |||
| private Thread errorThread; | |||
| private Thread inputThread; | |||
| private OutputStream out, err; | |||
| public PumpStreamHandler( OutputStream out, OutputStream err ) | |||
| { | |||
| this.out = out; | |||
| this.err = err; | |||
| } | |||
| public PumpStreamHandler( OutputStream outAndErr ) | |||
| { | |||
| this( outAndErr, outAndErr ); | |||
| } | |||
| public PumpStreamHandler() | |||
| { | |||
| this( System.out, System.err ); | |||
| } | |||
| public void setProcessErrorStream( InputStream is ) | |||
| { | |||
| createProcessErrorPump( is, err ); | |||
| } | |||
| public void setProcessInputStream( OutputStream os ) { } | |||
| public void setProcessOutputStream( InputStream is ) | |||
| { | |||
| createProcessOutputPump( is, out ); | |||
| } | |||
| public void start() | |||
| { | |||
| inputThread.start(); | |||
| errorThread.start(); | |||
| } | |||
| public void stop() | |||
| { | |||
| try | |||
| { | |||
| inputThread.join(); | |||
| } | |||
| catch( InterruptedException e ) | |||
| {} | |||
| try | |||
| { | |||
| errorThread.join(); | |||
| } | |||
| catch( InterruptedException e ) | |||
| {} | |||
| try | |||
| { | |||
| err.flush(); | |||
| } | |||
| catch( IOException e ) | |||
| {} | |||
| try | |||
| { | |||
| out.flush(); | |||
| } | |||
| catch( IOException e ) | |||
| {} | |||
| } | |||
| protected OutputStream getErr() | |||
| { | |||
| return err; | |||
| } | |||
| protected OutputStream getOut() | |||
| { | |||
| return out; | |||
| } | |||
| protected void createProcessErrorPump( InputStream is, OutputStream os ) | |||
| { | |||
| errorThread = createPump( is, os ); | |||
| } | |||
| protected void createProcessOutputPump( InputStream is, OutputStream os ) | |||
| { | |||
| inputThread = createPump( is, os ); | |||
| } | |||
| /** | |||
| * Creates a stream pumper to copy the given input stream to the given | |||
| * output stream. | |||
| * | |||
| * @param is Description of Parameter | |||
| * @param os Description of Parameter | |||
| * @return Description of the Returned Value | |||
| */ | |||
| protected Thread createPump( InputStream is, OutputStream os ) | |||
| { | |||
| final Thread result = new Thread( new StreamPumper( is, os ) ); | |||
| result.setDaemon( true ); | |||
| return result; | |||
| } | |||
| } | |||
| @@ -0,0 +1,239 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.FileOutputStream; | |||
| import java.io.IOException; | |||
| import java.io.PrintStream; | |||
| import java.util.Hashtable; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.Task; | |||
| import org.apache.tools.ant.types.EnumeratedAttribute; | |||
| /** | |||
| * This task is the manager for RecorderEntry's. It is this class that holds all | |||
| * entries, modifies them every time the <recorder> task is called, and | |||
| * addes them to the build listener process. | |||
| * | |||
| * @author <a href="mailto:jayglanville@home.com">J D Glanville</a> | |||
| * @version 0.5 | |||
| * @see RecorderEntry | |||
| */ | |||
| public class Recorder extends Task | |||
| { | |||
| /** | |||
| * The list of recorder entries. | |||
| */ | |||
| private static Hashtable recorderEntries = new Hashtable(); | |||
| ////////////////////////////////////////////////////////////////////// | |||
| // 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; | |||
| /** | |||
| * 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. | |||
| * | |||
| * @param append The new Append value | |||
| */ | |||
| public void setAppend( boolean append ) | |||
| { | |||
| this.append = new Boolean( append ); | |||
| } | |||
| /** | |||
| * Sets the level to which this recorder entry should log to. | |||
| * | |||
| * @param level The new Loglevel value | |||
| * @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; | |||
| } | |||
| } | |||
| ////////////////////////////////////////////////////////////////////// | |||
| // 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; | |||
| } | |||
| ////////////////////////////////////////////////////////////////////// | |||
| // CORE / MAIN BODY | |||
| /** | |||
| * The main execution. | |||
| * | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| 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 ); | |||
| } | |||
| /** | |||
| * Gets the recorder that's associated with the passed in name. If the | |||
| * recorder doesn't exist, then a new one is created. | |||
| * | |||
| * @param name Description of Parameter | |||
| * @param proj Description of Parameter | |||
| * @return The Recorder value | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| 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; | |||
| } | |||
| ////////////////////////////////////////////////////////////////////// | |||
| // INNER CLASSES | |||
| /** | |||
| * A list of possible values for the <code>setAction()</code> method. | |||
| * Possible values include: start and stop. | |||
| * | |||
| * @author RT | |||
| */ | |||
| public static class ActionChoices extends EnumeratedAttribute | |||
| { | |||
| private final static String[] values = {"start", "stop"}; | |||
| public String[] getValues() | |||
| { | |||
| return values; | |||
| } | |||
| } | |||
| /** | |||
| * A list of possible values for the <code>setLoglevel()</code> method. | |||
| * Possible values include: error, warn, info, verbose, debug. | |||
| * | |||
| * @author RT | |||
| */ | |||
| public static class VerbosityLevelChoices extends EnumeratedAttribute | |||
| { | |||
| private final static String[] values = {"error", "warn", "info", | |||
| "verbose", "debug"}; | |||
| public String[] getValues() | |||
| { | |||
| return values; | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,208 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.PrintStream; | |||
| import org.apache.tools.ant.BuildEvent; | |||
| import org.apache.tools.ant.BuildLogger; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.util.StringUtils; | |||
| /** | |||
| * This is a class that represents a recorder. This is the listener to the build | |||
| * process. | |||
| * | |||
| * @author <a href="mailto:jayglanville@home.com">J D Glanville</a> | |||
| * @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; | |||
| ////////////////////////////////////////////////////////////////////// | |||
| // CONSTRUCTORS / INITIALIZERS | |||
| /** | |||
| * @param name The name of this recorder (used as the filename). | |||
| */ | |||
| protected RecorderEntry( String name ) | |||
| { | |||
| filename = name; | |||
| } | |||
| 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" ); | |||
| } | |||
| } | |||
| public void setEmacsMode( boolean emacsMode ) | |||
| { | |||
| throw new java.lang.RuntimeException( "Method setEmacsMode() not yet implemented." ); | |||
| } | |||
| public void setErrorPrintStream( PrintStream err ) | |||
| { | |||
| out = err; | |||
| } | |||
| public void setMessageOutputLevel( int level ) | |||
| { | |||
| if( level >= Project.MSG_ERR && level <= Project.MSG_DEBUG ) | |||
| loglevel = level; | |||
| } | |||
| public void setOutputPrintStream( PrintStream output ) | |||
| { | |||
| out = output; | |||
| } | |||
| /** | |||
| * 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(); | |||
| } | |||
| ////////////////////////////////////////////////////////////////////// | |||
| // ACCESSOR METHODS | |||
| /** | |||
| * @return the name of the file the output is sent to. | |||
| */ | |||
| public String getFilename() | |||
| { | |||
| return filename; | |||
| } | |||
| public void buildFinished( BuildEvent event ) | |||
| { | |||
| log( "< BUILD FINISHED", Project.MSG_DEBUG ); | |||
| Throwable error = event.getException(); | |||
| if( error == null ) | |||
| { | |||
| out.println( StringUtils.LINE_SEP + "BUILD SUCCESSFUL" ); | |||
| } | |||
| else | |||
| { | |||
| out.println( StringUtils.LINE_SEP + "BUILD FAILED" + StringUtils.LINE_SEP ); | |||
| error.printStackTrace( out ); | |||
| } | |||
| out.flush(); | |||
| out.close(); | |||
| } | |||
| public void buildStarted( BuildEvent event ) | |||
| { | |||
| log( "> BUILD STARTED", Project.MSG_DEBUG ); | |||
| } | |||
| 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() ); | |||
| } | |||
| 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 targetStarted( BuildEvent event ) | |||
| { | |||
| log( ">> TARGET STARTED -- " + event.getTarget(), Project.MSG_DEBUG ); | |||
| log( StringUtils.LINE_SEP + event.getTarget().getName() + ":", Project.MSG_INFO ); | |||
| targetStartTime = System.currentTimeMillis(); | |||
| } | |||
| public void taskFinished( BuildEvent event ) | |||
| { | |||
| log( "<<< TASK FINISHED -- " + event.getTask(), Project.MSG_DEBUG ); | |||
| out.flush(); | |||
| } | |||
| public void taskStarted( BuildEvent event ) | |||
| { | |||
| log( ">>> TASK STARTED -- " + event.getTask(), Project.MSG_DEBUG ); | |||
| } | |||
| /** | |||
| * 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 ); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,92 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.File; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Task; | |||
| /** | |||
| * Renames a file. | |||
| * | |||
| * @author haas@softwired.ch | |||
| * @deprecated The rename task is deprecated. Use move instead. | |||
| */ | |||
| public class Rename extends Task | |||
| { | |||
| private boolean replace = true; | |||
| private File dest; | |||
| private File src; | |||
| /** | |||
| * Sets the new name of the file. | |||
| * | |||
| * @param dest the new name of the file. | |||
| */ | |||
| public void setDest( File dest ) | |||
| { | |||
| this.dest = dest; | |||
| } | |||
| /** | |||
| * Sets wheter an existing file should be replaced. | |||
| * | |||
| * @param replace <code>on</code>, if an existing file should be replaced. | |||
| */ | |||
| public void setReplace( String replace ) | |||
| { | |||
| this.replace = project.toBoolean( replace ); | |||
| } | |||
| /** | |||
| * Sets the file to be renamed. | |||
| * | |||
| * @param src the file to rename | |||
| */ | |||
| public void setSrc( File src ) | |||
| { | |||
| this.src = src; | |||
| } | |||
| /** | |||
| * Renames the file <code>src</code> to <code>dest</code> | |||
| * | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| log( "DEPRECATED - The rename task is deprecated. Use move instead." ); | |||
| if( dest == null ) | |||
| { | |||
| throw new BuildException( "dest attribute is required", location ); | |||
| } | |||
| if( src == null ) | |||
| { | |||
| throw new BuildException( "src attribute is required", location ); | |||
| } | |||
| if( replace && dest.exists() ) | |||
| { | |||
| if( !dest.delete() ) | |||
| { | |||
| throw new BuildException( "Unable to remove existing file " + | |||
| dest ); | |||
| } | |||
| } | |||
| if( !src.renameTo( dest ) ) | |||
| { | |||
| throw new BuildException( "Unable to rename " + src + " to " + | |||
| dest ); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,591 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.BufferedReader; | |||
| import java.io.BufferedWriter; | |||
| import java.io.File; | |||
| import java.io.FileInputStream; | |||
| import java.io.FileNotFoundException; | |||
| import java.io.FileOutputStream; | |||
| import java.io.FileReader; | |||
| import java.io.FileWriter; | |||
| import java.io.IOException; | |||
| import java.io.InputStreamReader; | |||
| import java.io.OutputStreamWriter; | |||
| import java.io.Reader; | |||
| import java.io.Writer; | |||
| 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.util.FileUtils; | |||
| /** | |||
| * Replaces all occurrences of one or more string tokens with given values in | |||
| * the indicated files. Each value can be either a string or the value of a | |||
| * property available in a designated property file. | |||
| * | |||
| * @author Stefano Mazzocchi <a href="mailto:stefano@apache.org"> | |||
| * stefano@apache.org</a> | |||
| * @author <a href="mailto:erik@desknetinc.com">Erik Langenbach</a> | |||
| */ | |||
| public class Replace extends MatchingTask | |||
| { | |||
| private File src = null; | |||
| private NestedString token = null; | |||
| private NestedString value = new NestedString(); | |||
| private File propertyFile = null; | |||
| private Properties properties = null; | |||
| private Vector replacefilters = new Vector(); | |||
| private File dir = null; | |||
| private boolean summary = false; | |||
| /** | |||
| * The encoding used to read and write files - if null, uses default | |||
| */ | |||
| private String encoding = null; | |||
| private FileUtils fileUtils = FileUtils.newFileUtils(); | |||
| private int fileCount; | |||
| private int replaceCount; | |||
| /** | |||
| * Set the source files path when using matching tasks. | |||
| * | |||
| * @param dir The new Dir value | |||
| */ | |||
| public void setDir( File dir ) | |||
| { | |||
| this.dir = dir; | |||
| } | |||
| /** | |||
| * Set the file encoding to use on the files read and written by replace | |||
| * | |||
| * @param encoding the encoding to use on the files | |||
| */ | |||
| public void setEncoding( String encoding ) | |||
| { | |||
| this.encoding = encoding; | |||
| } | |||
| /** | |||
| * Set the source file. | |||
| * | |||
| * @param file The new File value | |||
| */ | |||
| public void setFile( File file ) | |||
| { | |||
| this.src = file; | |||
| } | |||
| /** | |||
| * Sets a file to be searched for property values. | |||
| * | |||
| * @param filename The new PropertyFile value | |||
| */ | |||
| public void setPropertyFile( File filename ) | |||
| { | |||
| propertyFile = filename; | |||
| } | |||
| /** | |||
| * Request a summary | |||
| * | |||
| * @param summary true if you would like a summary logged of the replace | |||
| * operation | |||
| */ | |||
| public void setSummary( boolean summary ) | |||
| { | |||
| this.summary = summary; | |||
| } | |||
| /** | |||
| * Set the string token to replace. | |||
| * | |||
| * @param token The new Token value | |||
| */ | |||
| public void setToken( String token ) | |||
| { | |||
| createReplaceToken().addText( token ); | |||
| } | |||
| /** | |||
| * Set the string value to use as token replacement. | |||
| * | |||
| * @param value The new Value value | |||
| */ | |||
| public void setValue( String value ) | |||
| { | |||
| createReplaceValue().addText( value ); | |||
| } | |||
| public Properties getProperties( File propertyFile ) | |||
| throws BuildException | |||
| { | |||
| Properties properties = new Properties(); | |||
| try | |||
| { | |||
| properties.load( new FileInputStream( propertyFile ) ); | |||
| } | |||
| catch( FileNotFoundException e ) | |||
| { | |||
| String message = "Property file (" + propertyFile.getPath() + ") not found."; | |||
| throw new BuildException( message ); | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| String message = "Property file (" + propertyFile.getPath() + ") cannot be loaded."; | |||
| throw new BuildException( message ); | |||
| } | |||
| return properties; | |||
| } | |||
| /** | |||
| * Nested <replacetoken> element. | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public NestedString createReplaceToken() | |||
| { | |||
| if( token == null ) | |||
| { | |||
| token = new NestedString(); | |||
| } | |||
| return token; | |||
| } | |||
| /** | |||
| * Nested <replacevalue> element. | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public NestedString createReplaceValue() | |||
| { | |||
| return value; | |||
| } | |||
| /** | |||
| * Add nested <replacefilter> element. | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public Replacefilter createReplacefilter() | |||
| { | |||
| Replacefilter filter = new Replacefilter(); | |||
| replacefilters.addElement( filter ); | |||
| return filter; | |||
| } | |||
| /** | |||
| * Do the execution. | |||
| * | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| validateAttributes(); | |||
| if( propertyFile != null ) | |||
| { | |||
| properties = getProperties( propertyFile ); | |||
| } | |||
| validateReplacefilters(); | |||
| fileCount = 0; | |||
| replaceCount = 0; | |||
| if( src != null ) | |||
| { | |||
| processFile( src ); | |||
| } | |||
| if( dir != null ) | |||
| { | |||
| DirectoryScanner ds = super.getDirectoryScanner( dir ); | |||
| String[] srcs = ds.getIncludedFiles(); | |||
| for( int i = 0; i < srcs.length; i++ ) | |||
| { | |||
| File file = new File( dir, srcs[i] ); | |||
| processFile( file ); | |||
| } | |||
| } | |||
| if( summary ) | |||
| { | |||
| log( "Replaced " + replaceCount + " occurrences in " + fileCount + " files.", Project.MSG_INFO ); | |||
| } | |||
| } | |||
| /** | |||
| * Validate attributes provided for this task in .xml build file. | |||
| * | |||
| * @exception BuildException if any supplied attribute is invalid or any | |||
| * mandatory attribute is missing | |||
| */ | |||
| public void validateAttributes() | |||
| throws BuildException | |||
| { | |||
| if( src == null && dir == null ) | |||
| { | |||
| String message = "Either the file or the dir attribute " + "must be specified"; | |||
| throw new BuildException( message, location ); | |||
| } | |||
| if( propertyFile != null && !propertyFile.exists() ) | |||
| { | |||
| String message = "Property file " + propertyFile.getPath() + " does not exist."; | |||
| throw new BuildException( message, location ); | |||
| } | |||
| if( token == null && replacefilters.size() == 0 ) | |||
| { | |||
| String message = "Either token or a nested replacefilter " | |||
| + "must be specified"; | |||
| throw new BuildException( message, location ); | |||
| } | |||
| if( token != null && "".equals( token.getText() ) ) | |||
| { | |||
| String message = "The token attribute must not be an empty string."; | |||
| throw new BuildException( message, location ); | |||
| } | |||
| } | |||
| /** | |||
| * Validate nested elements. | |||
| * | |||
| * @exception BuildException if any supplied attribute is invalid or any | |||
| * mandatory attribute is missing | |||
| */ | |||
| public void validateReplacefilters() | |||
| throws BuildException | |||
| { | |||
| for( int i = 0; i < replacefilters.size(); i++ ) | |||
| { | |||
| Replacefilter element = ( Replacefilter )replacefilters.elementAt( i ); | |||
| element.validate(); | |||
| } | |||
| } | |||
| /** | |||
| * Perform the replacement on the given file. The replacement is performed | |||
| * on a temporary file which then replaces the original file. | |||
| * | |||
| * @param src the source file | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| private void processFile( File src ) | |||
| throws BuildException | |||
| { | |||
| if( !src.exists() ) | |||
| { | |||
| throw new BuildException( "Replace: source file " + src.getPath() + " doesn't exist", location ); | |||
| } | |||
| File temp = fileUtils.createTempFile( "rep", ".tmp", | |||
| fileUtils.getParentFile( src ) ); | |||
| Reader reader = null; | |||
| Writer writer = null; | |||
| try | |||
| { | |||
| reader = encoding == null ? new FileReader( src ) | |||
| : new InputStreamReader( new FileInputStream( src ), encoding ); | |||
| writer = encoding == null ? new FileWriter( temp ) | |||
| : new OutputStreamWriter( new FileOutputStream( temp ), encoding ); | |||
| BufferedReader br = new BufferedReader( reader ); | |||
| BufferedWriter bw = new BufferedWriter( writer ); | |||
| // read the entire file into a StringBuffer | |||
| // size of work buffer may be bigger than needed | |||
| // when multibyte characters exist in the source file | |||
| // but then again, it might be smaller than needed on | |||
| // platforms like Windows where length can't be trusted | |||
| int fileLengthInBytes = ( int )( src.length() ); | |||
| StringBuffer tmpBuf = new StringBuffer( fileLengthInBytes ); | |||
| int readChar = 0; | |||
| int totread = 0; | |||
| while( true ) | |||
| { | |||
| readChar = br.read(); | |||
| if( readChar < 0 ) | |||
| { | |||
| break; | |||
| } | |||
| tmpBuf.append( ( char )readChar ); | |||
| totread++; | |||
| } | |||
| // create a String so we can use indexOf | |||
| String buf = tmpBuf.toString(); | |||
| //Preserve original string (buf) so we can compare the result | |||
| String newString = new String( buf ); | |||
| if( token != null ) | |||
| { | |||
| // line separators in values and tokens are "\n" | |||
| // in order to compare with the file contents, replace them | |||
| // as needed | |||
| String linesep = System.getProperty( "line.separator" ); | |||
| String val = stringReplace( value.getText(), "\n", linesep ); | |||
| String tok = stringReplace( token.getText(), "\n", linesep ); | |||
| // for each found token, replace with value | |||
| log( "Replacing in " + src.getPath() + ": " + token.getText() + " --> " + value.getText(), Project.MSG_VERBOSE ); | |||
| newString = stringReplace( newString, tok, val ); | |||
| } | |||
| if( replacefilters.size() > 0 ) | |||
| { | |||
| newString = processReplacefilters( newString, src.getPath() ); | |||
| } | |||
| boolean changes = !newString.equals( buf ); | |||
| if( changes ) | |||
| { | |||
| bw.write( newString, 0, newString.length() ); | |||
| bw.flush(); | |||
| } | |||
| // cleanup | |||
| bw.close(); | |||
| writer = null; | |||
| br.close(); | |||
| reader = null; | |||
| // If there were changes, move the new one to the old one; | |||
| // otherwise, delete the new one | |||
| if( changes ) | |||
| { | |||
| ++fileCount; | |||
| src.delete(); | |||
| temp.renameTo( src ); | |||
| temp = null; | |||
| } | |||
| } | |||
| catch( IOException ioe ) | |||
| { | |||
| throw new BuildException( "IOException in " + src + " - " + | |||
| ioe.getClass().getName() + ":" + ioe.getMessage(), ioe, location ); | |||
| } | |||
| finally | |||
| { | |||
| if( reader != null ) | |||
| { | |||
| try | |||
| { | |||
| reader.close(); | |||
| } | |||
| catch( IOException e ) | |||
| {} | |||
| } | |||
| if( writer != null ) | |||
| { | |||
| try | |||
| { | |||
| writer.close(); | |||
| } | |||
| catch( IOException e ) | |||
| {} | |||
| } | |||
| if( temp != null ) | |||
| { | |||
| temp.delete(); | |||
| } | |||
| } | |||
| } | |||
| private String processReplacefilters( String buffer, String filename ) | |||
| { | |||
| String newString = new String( buffer ); | |||
| for( int i = 0; i < replacefilters.size(); i++ ) | |||
| { | |||
| Replacefilter filter = ( Replacefilter )replacefilters.elementAt( i ); | |||
| //for each found token, replace with value | |||
| log( "Replacing in " + filename + ": " + filter.getToken() + " --> " + filter.getReplaceValue(), Project.MSG_VERBOSE ); | |||
| newString = stringReplace( newString, filter.getToken(), filter.getReplaceValue() ); | |||
| } | |||
| return newString; | |||
| } | |||
| /** | |||
| * Replace occurrences of str1 in string str with str2 | |||
| * | |||
| * @param str Description of Parameter | |||
| * @param str1 Description of Parameter | |||
| * @param str2 Description of Parameter | |||
| * @return Description of the Returned Value | |||
| */ | |||
| private String stringReplace( String str, String str1, String str2 ) | |||
| { | |||
| StringBuffer ret = new StringBuffer(); | |||
| int start = 0; | |||
| int found = str.indexOf( str1 ); | |||
| while( found >= 0 ) | |||
| { | |||
| // write everything up to the found str1 | |||
| if( found > start ) | |||
| { | |||
| ret.append( str.substring( start, found ) ); | |||
| } | |||
| // write the replacement str2 | |||
| if( str2 != null ) | |||
| { | |||
| ret.append( str2 ); | |||
| } | |||
| // search again | |||
| start = found + str1.length(); | |||
| found = str.indexOf( str1, start ); | |||
| ++replaceCount; | |||
| } | |||
| // write the remaining characters | |||
| if( str.length() > start ) | |||
| { | |||
| ret.append( str.substring( start, str.length() ) ); | |||
| } | |||
| return ret.toString(); | |||
| } | |||
| //Inner class | |||
| public class NestedString | |||
| { | |||
| private StringBuffer buf = new StringBuffer(); | |||
| public String getText() | |||
| { | |||
| return buf.toString(); | |||
| } | |||
| public void addText( String val ) | |||
| { | |||
| buf.append( val ); | |||
| } | |||
| } | |||
| //Inner class | |||
| public class Replacefilter | |||
| { | |||
| private String property; | |||
| private String token; | |||
| private String value; | |||
| public void setProperty( String property ) | |||
| { | |||
| this.property = property; | |||
| } | |||
| public void setToken( String token ) | |||
| { | |||
| this.token = token; | |||
| } | |||
| public void setValue( String value ) | |||
| { | |||
| this.value = value; | |||
| } | |||
| public String getProperty() | |||
| { | |||
| return property; | |||
| } | |||
| public String getReplaceValue() | |||
| { | |||
| if( property != null ) | |||
| { | |||
| return ( String )properties.getProperty( property ); | |||
| } | |||
| else if( value != null ) | |||
| { | |||
| return value; | |||
| } | |||
| else if( Replace.this.value != null ) | |||
| { | |||
| return Replace.this.value.getText(); | |||
| } | |||
| else | |||
| { | |||
| //Default is empty string | |||
| return new String( "" ); | |||
| } | |||
| } | |||
| public String getToken() | |||
| { | |||
| return token; | |||
| } | |||
| public String getValue() | |||
| { | |||
| return value; | |||
| } | |||
| public void validate() | |||
| throws BuildException | |||
| { | |||
| //Validate mandatory attributes | |||
| if( token == null ) | |||
| { | |||
| String message = "token is a mandatory attribute " + "of replacefilter."; | |||
| throw new BuildException( message ); | |||
| } | |||
| if( "".equals( token ) ) | |||
| { | |||
| String message = "The token attribute must not be an empty string."; | |||
| throw new BuildException( message ); | |||
| } | |||
| //value and property are mutually exclusive attributes | |||
| if( ( value != null ) && ( property != null ) ) | |||
| { | |||
| String message = "Either value or property " + "can be specified, but a replacefilter " + "element cannot have both."; | |||
| throw new BuildException( message ); | |||
| } | |||
| if( ( property != null ) ) | |||
| { | |||
| //the property attribute must have access to a property file | |||
| if( propertyFile == null ) | |||
| { | |||
| String message = "The replacefilter's property attribute " + "can only be used with the replacetask's " + "propertyFile attribute."; | |||
| throw new BuildException( message ); | |||
| } | |||
| //Make sure property exists in property file | |||
| if( properties == null || | |||
| properties.getProperty( property ) == null ) | |||
| { | |||
| String message = "property \"" + property + "\" was not found in " + propertyFile.getPath(); | |||
| throw new BuildException( message ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,688 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| import java.rmi.Remote; | |||
| import java.util.Vector; | |||
| import org.apache.tools.ant.AntClassLoader; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.DirectoryScanner; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.taskdefs.rmic.RmicAdapter; | |||
| import org.apache.tools.ant.taskdefs.rmic.RmicAdapterFactory; | |||
| import org.apache.tools.ant.types.Path; | |||
| import org.apache.tools.ant.types.Reference; | |||
| import org.apache.tools.ant.util.FileNameMapper; | |||
| import org.apache.tools.ant.util.SourceFileScanner; | |||
| /** | |||
| * Task to compile RMI stubs and skeletons. This task can take the following | |||
| * arguments: | |||
| * <ul> | |||
| * <li> base: The base directory for the compiled stubs and skeletons | |||
| * <li> class: The name of the class to generate the stubs from | |||
| * <li> stubVersion: The version of the stub prototol to use (1.1, 1.2, | |||
| * compat) | |||
| * <li> sourceBase: The base directory for the generated stubs and skeletons | |||
| * | |||
| * <li> classpath: Additional classpath, appended before the system classpath | |||
| * | |||
| * <li> iiop: Generate IIOP compatable output | |||
| * <li> iiopopts: Include IIOP options | |||
| * <li> idl: Generate IDL output | |||
| * <li> idlopts: Include IDL options | |||
| * <li> includeantruntime | |||
| * <li> includejavaruntime | |||
| * <li> extdirs | |||
| * </ul> | |||
| * Of these arguments, <b>base</b> is required. <p> | |||
| * | |||
| * If classname is specified then only that classname will be compiled. If it is | |||
| * absent, then <b>base</b> is traversed for classes according to patterns. <p> | |||
| * | |||
| * | |||
| * | |||
| * @author duncan@x180.com | |||
| * @author ludovic.claude@websitewatchers.co.uk | |||
| * @author David Maclean <a href="mailto:david@cm.co.za">david@cm.co.za</a> | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| * @author Takashi Okamoto tokamoto@rd.nttdata.co.jp | |||
| */ | |||
| public class Rmic extends MatchingTask | |||
| { | |||
| private final static String FAIL_MSG | |||
| = "Rmic failed, messages should have been provided."; | |||
| private boolean verify = false; | |||
| private boolean filtering = false; | |||
| private boolean iiop = false; | |||
| private boolean idl = false; | |||
| private boolean debug = false; | |||
| private boolean includeAntRuntime = true; | |||
| private boolean includeJavaRuntime = false; | |||
| private Vector compileList = new Vector(); | |||
| private ClassLoader loader = null; | |||
| private File baseDir; | |||
| private String classname; | |||
| private Path compileClasspath; | |||
| private Path extdirs; | |||
| private String idlopts; | |||
| private String iiopopts; | |||
| private File sourceBase; | |||
| private String stubVersion; | |||
| /** | |||
| * Sets the base directory to output generated class. | |||
| * | |||
| * @param base The new Base value | |||
| */ | |||
| public void setBase( File base ) | |||
| { | |||
| this.baseDir = base; | |||
| } | |||
| /** | |||
| * Sets the class name to compile. | |||
| * | |||
| * @param classname The new Classname value | |||
| */ | |||
| public void setClassname( String classname ) | |||
| { | |||
| this.classname = classname; | |||
| } | |||
| /** | |||
| * Set the classpath to be used for this compilation. | |||
| * | |||
| * @param classpath The new Classpath value | |||
| */ | |||
| public void setClasspath( Path classpath ) | |||
| { | |||
| if( compileClasspath == null ) | |||
| { | |||
| compileClasspath = classpath; | |||
| } | |||
| else | |||
| { | |||
| compileClasspath.append( classpath ); | |||
| } | |||
| } | |||
| /** | |||
| * Adds a reference to a CLASSPATH defined elsewhere. | |||
| * | |||
| * @param r The new ClasspathRef value | |||
| */ | |||
| public void setClasspathRef( Reference r ) | |||
| { | |||
| createClasspath().setRefid( r ); | |||
| } | |||
| /** | |||
| * Sets the debug flag. | |||
| * | |||
| * @param debug The new Debug value | |||
| */ | |||
| public void setDebug( boolean debug ) | |||
| { | |||
| this.debug = debug; | |||
| } | |||
| /** | |||
| * Sets the extension directories that will be used during the compilation. | |||
| * | |||
| * @param extdirs The new Extdirs value | |||
| */ | |||
| public void setExtdirs( Path extdirs ) | |||
| { | |||
| if( this.extdirs == null ) | |||
| { | |||
| this.extdirs = extdirs; | |||
| } | |||
| else | |||
| { | |||
| this.extdirs.append( extdirs ); | |||
| } | |||
| } | |||
| public void setFiltering( boolean filter ) | |||
| { | |||
| filtering = filter; | |||
| } | |||
| /** | |||
| * Indicates that IDL output should be generated. This defaults to false if | |||
| * not set. | |||
| * | |||
| * @param idl The new Idl value | |||
| */ | |||
| public void setIdl( boolean idl ) | |||
| { | |||
| this.idl = idl; | |||
| } | |||
| /** | |||
| * pass additional arguments for idl compile | |||
| * | |||
| * @param idlopts The new Idlopts value | |||
| */ | |||
| public void setIdlopts( String idlopts ) | |||
| { | |||
| this.idlopts = idlopts; | |||
| } | |||
| /** | |||
| * Indicates that IIOP compatible stubs should be generated. This defaults | |||
| * to false if not set. | |||
| * | |||
| * @param iiop The new Iiop value | |||
| */ | |||
| public void setIiop( boolean iiop ) | |||
| { | |||
| this.iiop = iiop; | |||
| } | |||
| /** | |||
| * pass additional arguments for iiop | |||
| * | |||
| * @param iiopopts The new Iiopopts value | |||
| */ | |||
| public void setIiopopts( String iiopopts ) | |||
| { | |||
| this.iiopopts = iiopopts; | |||
| } | |||
| /** | |||
| * Include ant's own classpath in this task's classpath? | |||
| * | |||
| * @param include The new Includeantruntime value | |||
| */ | |||
| public void setIncludeantruntime( boolean include ) | |||
| { | |||
| includeAntRuntime = include; | |||
| } | |||
| /** | |||
| * Sets whether or not to include the java runtime libraries to this task's | |||
| * classpath. | |||
| * | |||
| * @param include The new Includejavaruntime value | |||
| */ | |||
| public void setIncludejavaruntime( boolean include ) | |||
| { | |||
| includeJavaRuntime = include; | |||
| } | |||
| /** | |||
| * Sets the source dirs to find the source java files. | |||
| * | |||
| * @param sourceBase The new SourceBase value | |||
| */ | |||
| public void setSourceBase( File sourceBase ) | |||
| { | |||
| this.sourceBase = sourceBase; | |||
| } | |||
| /** | |||
| * Sets the stub version. | |||
| * | |||
| * @param stubVersion The new StubVersion value | |||
| */ | |||
| public void setStubVersion( String stubVersion ) | |||
| { | |||
| this.stubVersion = stubVersion; | |||
| } | |||
| /** | |||
| * Indicates that the classes found by the directory match should be checked | |||
| * to see if they implement java.rmi.Remote. This defaults to false if not | |||
| * set. | |||
| * | |||
| * @param verify The new Verify value | |||
| */ | |||
| public void setVerify( boolean verify ) | |||
| { | |||
| this.verify = verify; | |||
| } | |||
| /** | |||
| * Gets the base directory to output generated class. | |||
| * | |||
| * @return The Base value | |||
| */ | |||
| public File getBase() | |||
| { | |||
| return this.baseDir; | |||
| } | |||
| /** | |||
| * Gets the class name to compile. | |||
| * | |||
| * @return The Classname value | |||
| */ | |||
| public String getClassname() | |||
| { | |||
| return classname; | |||
| } | |||
| /** | |||
| * Gets the classpath. | |||
| * | |||
| * @return The Classpath value | |||
| */ | |||
| public Path getClasspath() | |||
| { | |||
| return compileClasspath; | |||
| } | |||
| public Vector getCompileList() | |||
| { | |||
| return compileList; | |||
| } | |||
| /** | |||
| * Gets the debug flag. | |||
| * | |||
| * @return The Debug value | |||
| */ | |||
| public boolean getDebug() | |||
| { | |||
| return debug; | |||
| } | |||
| /** | |||
| * Gets the extension directories that will be used during the compilation. | |||
| * | |||
| * @return The Extdirs value | |||
| */ | |||
| public Path getExtdirs() | |||
| { | |||
| return extdirs; | |||
| } | |||
| /** | |||
| * Gets file list to compile. | |||
| * | |||
| * @return The FileList value | |||
| */ | |||
| public Vector getFileList() | |||
| { | |||
| return compileList; | |||
| } | |||
| public boolean getFiltering() | |||
| { | |||
| return filtering; | |||
| } | |||
| /* | |||
| * Gets IDL flags. | |||
| */ | |||
| public boolean getIdl() | |||
| { | |||
| return idl; | |||
| } | |||
| /** | |||
| * Gets additional arguments for idl compile. | |||
| * | |||
| * @return The Idlopts value | |||
| */ | |||
| public String getIdlopts() | |||
| { | |||
| return idlopts; | |||
| } | |||
| /** | |||
| * Gets iiop flags. | |||
| * | |||
| * @return The Iiop value | |||
| */ | |||
| public boolean getIiop() | |||
| { | |||
| return iiop; | |||
| } | |||
| /** | |||
| * Gets additional arguments for iiop. | |||
| * | |||
| * @return The Iiopopts value | |||
| */ | |||
| public String getIiopopts() | |||
| { | |||
| return iiopopts; | |||
| } | |||
| /** | |||
| * Gets whether or not the ant classpath is to be included in the task's | |||
| * classpath. | |||
| * | |||
| * @return The Includeantruntime value | |||
| */ | |||
| public boolean getIncludeantruntime() | |||
| { | |||
| return includeAntRuntime; | |||
| } | |||
| /** | |||
| * Gets whether or not the java runtime should be included in this task's | |||
| * classpath. | |||
| * | |||
| * @return The Includejavaruntime value | |||
| */ | |||
| public boolean getIncludejavaruntime() | |||
| { | |||
| return includeJavaRuntime; | |||
| } | |||
| /** | |||
| * Classloader for the user-specified classpath. | |||
| * | |||
| * @return The Loader value | |||
| */ | |||
| public ClassLoader getLoader() | |||
| { | |||
| return loader; | |||
| } | |||
| /** | |||
| * Returns the topmost interface that extends Remote for a given class - if | |||
| * one exists. | |||
| * | |||
| * @param testClass Description of Parameter | |||
| * @return The RemoteInterface value | |||
| */ | |||
| public Class getRemoteInterface( Class testClass ) | |||
| { | |||
| if( Remote.class.isAssignableFrom( testClass ) ) | |||
| { | |||
| Class[] interfaces = testClass.getInterfaces(); | |||
| if( interfaces != null ) | |||
| { | |||
| for( int i = 0; i < interfaces.length; i++ ) | |||
| { | |||
| if( Remote.class.isAssignableFrom( interfaces[i] ) ) | |||
| { | |||
| return interfaces[i]; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| return null; | |||
| } | |||
| /** | |||
| * Gets the source dirs to find the source java files. | |||
| * | |||
| * @return The SourceBase value | |||
| */ | |||
| public File getSourceBase() | |||
| { | |||
| return sourceBase; | |||
| } | |||
| public String getStubVersion() | |||
| { | |||
| return stubVersion; | |||
| } | |||
| /** | |||
| * Get verify flag. | |||
| * | |||
| * @return The Verify value | |||
| */ | |||
| public boolean getVerify() | |||
| { | |||
| return verify; | |||
| } | |||
| /** | |||
| * Load named class and test whether it can be rmic'ed | |||
| * | |||
| * @param classname Description of Parameter | |||
| * @return The ValidRmiRemote value | |||
| */ | |||
| public boolean isValidRmiRemote( String classname ) | |||
| { | |||
| try | |||
| { | |||
| Class testClass = loader.loadClass( classname ); | |||
| // One cannot RMIC an interface for "classic" RMI (JRMP) | |||
| if( testClass.isInterface() && !iiop && !idl ) | |||
| { | |||
| return false; | |||
| } | |||
| return isValidRmiRemote( testClass ); | |||
| } | |||
| catch( ClassNotFoundException e ) | |||
| { | |||
| log( "Unable to verify class " + classname + | |||
| ". It could not be found.", Project.MSG_WARN ); | |||
| } | |||
| catch( NoClassDefFoundError e ) | |||
| { | |||
| log( "Unable to verify class " + classname + | |||
| ". It is not defined.", Project.MSG_WARN ); | |||
| } | |||
| catch( Throwable t ) | |||
| { | |||
| log( "Unable to verify class " + classname + | |||
| ". Loading caused Exception: " + | |||
| t.getMessage(), Project.MSG_WARN ); | |||
| } | |||
| // we only get here if an exception has been thrown | |||
| return false; | |||
| } | |||
| /** | |||
| * Creates a nested classpath element. | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public Path createClasspath() | |||
| { | |||
| if( compileClasspath == null ) | |||
| { | |||
| compileClasspath = new Path( project ); | |||
| } | |||
| return compileClasspath.createPath(); | |||
| } | |||
| /** | |||
| * Maybe creates a nested extdirs element. | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public Path createExtdirs() | |||
| { | |||
| if( extdirs == null ) | |||
| { | |||
| extdirs = new Path( project ); | |||
| } | |||
| return extdirs.createPath(); | |||
| } | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| if( baseDir == null ) | |||
| { | |||
| throw new BuildException( "base attribute must be set!", location ); | |||
| } | |||
| if( !baseDir.exists() ) | |||
| { | |||
| throw new BuildException( "base does not exist!", location ); | |||
| } | |||
| if( verify ) | |||
| { | |||
| log( "Verify has been turned on.", Project.MSG_INFO ); | |||
| } | |||
| String compiler = project.getProperty( "build.rmic" ); | |||
| RmicAdapter adapter = RmicAdapterFactory.getRmic( compiler, this ); | |||
| // now we need to populate the compiler adapter | |||
| adapter.setRmic( this ); | |||
| Path classpath = adapter.getClasspath(); | |||
| loader = new AntClassLoader( project, classpath ); | |||
| // scan base dirs to build up compile lists only if a | |||
| // specific classname is not given | |||
| if( classname == null ) | |||
| { | |||
| DirectoryScanner ds = this.getDirectoryScanner( baseDir ); | |||
| String[] files = ds.getIncludedFiles(); | |||
| scanDir( baseDir, files, adapter.getMapper() ); | |||
| } | |||
| else | |||
| { | |||
| // otherwise perform a timestamp comparison - at least | |||
| scanDir( baseDir, | |||
| new String[]{classname.replace( '.', File.separatorChar ) + ".class"}, | |||
| adapter.getMapper() ); | |||
| } | |||
| int fileCount = compileList.size(); | |||
| if( fileCount > 0 ) | |||
| { | |||
| log( "RMI Compiling " + fileCount + | |||
| " class" + ( fileCount > 1 ? "es" : "" ) + " to " + baseDir, | |||
| Project.MSG_INFO ); | |||
| // finally, lets execute the compiler!! | |||
| if( !adapter.execute() ) | |||
| { | |||
| throw new BuildException( FAIL_MSG, location ); | |||
| } | |||
| } | |||
| /* | |||
| * Move the generated source file to the base directory. If | |||
| * base directory and sourcebase are the same, the generated | |||
| * sources are already in place. | |||
| */ | |||
| if( null != sourceBase && !baseDir.equals( sourceBase ) ) | |||
| { | |||
| if( idl ) | |||
| { | |||
| log( "Cannot determine sourcefiles in idl mode, ", | |||
| Project.MSG_WARN ); | |||
| log( "sourcebase attribute will be ignored.", Project.MSG_WARN ); | |||
| } | |||
| else | |||
| { | |||
| for( int j = 0; j < fileCount; j++ ) | |||
| { | |||
| moveGeneratedFile( baseDir, sourceBase, | |||
| ( String )compileList.elementAt( j ), | |||
| adapter ); | |||
| } | |||
| } | |||
| } | |||
| compileList.removeAllElements(); | |||
| } | |||
| /** | |||
| * Scans the directory looking for class files to be compiled. The result is | |||
| * returned in the class variable compileList. | |||
| * | |||
| * @param baseDir Description of Parameter | |||
| * @param files Description of Parameter | |||
| * @param mapper Description of Parameter | |||
| */ | |||
| protected void scanDir( File baseDir, String files[], | |||
| FileNameMapper mapper ) | |||
| { | |||
| String[] newFiles = files; | |||
| if( idl ) | |||
| { | |||
| log( "will leave uptodate test to rmic implementation in idl mode.", | |||
| Project.MSG_VERBOSE ); | |||
| } | |||
| else if( iiop | |||
| && iiopopts != null && iiopopts.indexOf( "-always" ) > -1 ) | |||
| { | |||
| log( "no uptodate test as -always option has been specified", | |||
| Project.MSG_VERBOSE ); | |||
| } | |||
| else | |||
| { | |||
| SourceFileScanner sfs = new SourceFileScanner( this ); | |||
| newFiles = sfs.restrict( files, baseDir, baseDir, mapper ); | |||
| } | |||
| for( int i = 0; i < newFiles.length; i++ ) | |||
| { | |||
| String classname = newFiles[i].replace( File.separatorChar, '.' ); | |||
| classname = classname.substring( 0, classname.lastIndexOf( ".class" ) ); | |||
| compileList.addElement( classname ); | |||
| } | |||
| } | |||
| /** | |||
| * Check to see if the class or (super)interfaces implement java.rmi.Remote. | |||
| * | |||
| * @param testClass Description of Parameter | |||
| * @return The ValidRmiRemote value | |||
| */ | |||
| private boolean isValidRmiRemote( Class testClass ) | |||
| { | |||
| return getRemoteInterface( testClass ) != null; | |||
| } | |||
| /** | |||
| * Move the generated source file(s) to the base directory | |||
| * | |||
| * @param baseDir Description of Parameter | |||
| * @param sourceBaseFile Description of Parameter | |||
| * @param classname Description of Parameter | |||
| * @param adapter Description of Parameter | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| private void moveGeneratedFile( File baseDir, File sourceBaseFile, | |||
| String classname, | |||
| RmicAdapter adapter ) | |||
| throws BuildException | |||
| { | |||
| String classFileName = | |||
| classname.replace( '.', File.separatorChar ) + ".class"; | |||
| String[] generatedFiles = | |||
| adapter.getMapper().mapFileName( classFileName ); | |||
| for( int i = 0; i < generatedFiles.length; i++ ) | |||
| { | |||
| String sourceFileName = | |||
| classFileName.substring( 0, classFileName.length() - 6 ) + ".java"; | |||
| File oldFile = new File( baseDir, sourceFileName ); | |||
| File newFile = new File( sourceBaseFile, sourceFileName ); | |||
| try | |||
| { | |||
| project.copyFile( oldFile, newFile, filtering ); | |||
| oldFile.delete(); | |||
| } | |||
| catch( IOException ioe ) | |||
| { | |||
| String msg = "Failed to copy " + oldFile + " to " + | |||
| newFile + " due to " + ioe.getMessage(); | |||
| throw new BuildException( msg, ioe, location ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,867 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.BufferedOutputStream; | |||
| import java.io.BufferedReader; | |||
| import java.io.File; | |||
| import java.io.FileInputStream; | |||
| import java.io.FileOutputStream; | |||
| import java.io.FileReader; | |||
| import java.io.IOException; | |||
| import java.io.InputStreamReader; | |||
| import java.io.PrintStream; | |||
| import java.io.Reader; | |||
| import java.io.StringReader; | |||
| import java.sql.Connection; | |||
| import java.sql.DatabaseMetaData; | |||
| import java.sql.Driver; | |||
| import java.sql.ResultSet; | |||
| import java.sql.ResultSetMetaData; | |||
| import java.sql.SQLException; | |||
| import java.sql.SQLWarning; | |||
| import java.sql.Statement; | |||
| import java.util.Enumeration; | |||
| import java.util.Properties; | |||
| import java.util.StringTokenizer; | |||
| import java.util.Vector; | |||
| import org.apache.tools.ant.AntClassLoader; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.DirectoryScanner; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.ProjectHelper; | |||
| import org.apache.tools.ant.Task; | |||
| import org.apache.tools.ant.types.EnumeratedAttribute; | |||
| import org.apache.tools.ant.types.FileSet; | |||
| import org.apache.tools.ant.types.Path; | |||
| import org.apache.tools.ant.types.Reference; | |||
| /** | |||
| * Reads in a text file containing SQL statements seperated with semicolons and | |||
| * executes it in a given db. Comments may be created with REM -- or //. | |||
| * | |||
| * @author <a href="mailto:jeff@custommonkey.org">Jeff Martin</a> | |||
| * @author <A href="mailto:gholam@xtra.co.nz">Michael McCallum</A> | |||
| * @author <A href="mailto:tim.stephenson@sybase.com">Tim Stephenson</A> | |||
| */ | |||
| public class SQLExec extends Task | |||
| { | |||
| private int goodSql = 0, totalSql = 0; | |||
| private Vector filesets = new Vector(); | |||
| /** | |||
| * Database connection | |||
| */ | |||
| private Connection conn = null; | |||
| /** | |||
| * Autocommit flag. Default value is false | |||
| */ | |||
| private boolean autocommit = false; | |||
| /** | |||
| * SQL statement | |||
| */ | |||
| private Statement statement = null; | |||
| /** | |||
| * DB driver. | |||
| */ | |||
| private String driver = null; | |||
| /** | |||
| * DB url. | |||
| */ | |||
| private String url = null; | |||
| /** | |||
| * User name. | |||
| */ | |||
| private String userId = null; | |||
| /** | |||
| * Password | |||
| */ | |||
| private String password = null; | |||
| /** | |||
| * SQL input file | |||
| */ | |||
| private File srcFile = null; | |||
| /** | |||
| * SQL input command | |||
| */ | |||
| private String sqlCommand = ""; | |||
| /** | |||
| * SQL transactions to perform | |||
| */ | |||
| private Vector transactions = new Vector(); | |||
| /** | |||
| * SQL Statement delimiter | |||
| */ | |||
| private String delimiter = ";"; | |||
| /** | |||
| * The delimiter type indicating whether the delimiter will only be | |||
| * recognized on a line by itself | |||
| */ | |||
| private String delimiterType = DelimiterType.NORMAL; | |||
| /** | |||
| * Print SQL results. | |||
| */ | |||
| private boolean print = false; | |||
| /** | |||
| * Print header columns. | |||
| */ | |||
| private boolean showheaders = true; | |||
| /** | |||
| * Results Output file. | |||
| */ | |||
| private File output = null; | |||
| /** | |||
| * RDBMS Product needed for this SQL. | |||
| */ | |||
| private String rdbms = null; | |||
| /** | |||
| * RDBMS Version needed for this SQL. | |||
| */ | |||
| private String version = null; | |||
| /** | |||
| * Action to perform if an error is found | |||
| */ | |||
| private String onError = "abort"; | |||
| /** | |||
| * Encoding to use when reading SQL statements from a file | |||
| */ | |||
| private String encoding = null; | |||
| private Path classpath; | |||
| private AntClassLoader loader; | |||
| /** | |||
| * Set the autocommit flag for the DB connection. | |||
| * | |||
| * @param autocommit The new Autocommit value | |||
| */ | |||
| public void setAutocommit( boolean autocommit ) | |||
| { | |||
| this.autocommit = autocommit; | |||
| } | |||
| /** | |||
| * Set the classpath for loading the driver. | |||
| * | |||
| * @param classpath The new Classpath value | |||
| */ | |||
| public void setClasspath( Path classpath ) | |||
| { | |||
| if( this.classpath == null ) | |||
| { | |||
| this.classpath = classpath; | |||
| } | |||
| else | |||
| { | |||
| this.classpath.append( classpath ); | |||
| } | |||
| } | |||
| /** | |||
| * Set the classpath for loading the driver using the classpath reference. | |||
| * | |||
| * @param r The new ClasspathRef value | |||
| */ | |||
| public void setClasspathRef( Reference r ) | |||
| { | |||
| createClasspath().setRefid( r ); | |||
| } | |||
| /** | |||
| * Set the statement delimiter. <p> | |||
| * | |||
| * For example, set this to "go" and delimitertype to "ROW" for Sybase ASE | |||
| * or MS SQL Server.</p> | |||
| * | |||
| * @param delimiter The new Delimiter value | |||
| */ | |||
| public void setDelimiter( String delimiter ) | |||
| { | |||
| this.delimiter = delimiter; | |||
| } | |||
| /** | |||
| * Set the Delimiter type for this sql task. The delimiter type takes two | |||
| * values - normal and row. Normal means that any occurence of the delimiter | |||
| * terminate the SQL command whereas with row, only a line containing just | |||
| * the delimiter is recognized as the end of the command. | |||
| * | |||
| * @param delimiterType The new DelimiterType value | |||
| */ | |||
| public void setDelimiterType( DelimiterType delimiterType ) | |||
| { | |||
| this.delimiterType = delimiterType.getValue(); | |||
| } | |||
| /** | |||
| * Set the JDBC driver to be used. | |||
| * | |||
| * @param driver The new Driver value | |||
| */ | |||
| public void setDriver( String driver ) | |||
| { | |||
| this.driver = driver; | |||
| } | |||
| /** | |||
| * Set the file encoding to use on the sql files read in | |||
| * | |||
| * @param encoding the encoding to use on the files | |||
| */ | |||
| public void setEncoding( String encoding ) | |||
| { | |||
| this.encoding = encoding; | |||
| } | |||
| /** | |||
| * Set the action to perform onerror | |||
| * | |||
| * @param action The new Onerror value | |||
| */ | |||
| public void setOnerror( OnError action ) | |||
| { | |||
| this.onError = action.getValue(); | |||
| } | |||
| /** | |||
| * Set the output file. | |||
| * | |||
| * @param output The new Output value | |||
| */ | |||
| public void setOutput( File output ) | |||
| { | |||
| this.output = output; | |||
| } | |||
| /** | |||
| * Set the password for the DB connection. | |||
| * | |||
| * @param password The new Password value | |||
| */ | |||
| public void setPassword( String password ) | |||
| { | |||
| this.password = password; | |||
| } | |||
| /** | |||
| * Set the print flag. | |||
| * | |||
| * @param print The new Print value | |||
| */ | |||
| public void setPrint( boolean print ) | |||
| { | |||
| this.print = print; | |||
| } | |||
| /** | |||
| * Set the rdbms required | |||
| * | |||
| * @param vendor The new Rdbms value | |||
| */ | |||
| public void setRdbms( String vendor ) | |||
| { | |||
| this.rdbms = vendor.toLowerCase(); | |||
| } | |||
| /** | |||
| * Set the showheaders flag. | |||
| * | |||
| * @param showheaders The new Showheaders value | |||
| */ | |||
| public void setShowheaders( boolean showheaders ) | |||
| { | |||
| this.showheaders = showheaders; | |||
| } | |||
| /** | |||
| * Set the name of the sql file to be run. | |||
| * | |||
| * @param srcFile The new Src value | |||
| */ | |||
| public void setSrc( File srcFile ) | |||
| { | |||
| this.srcFile = srcFile; | |||
| } | |||
| /** | |||
| * Set the DB connection url. | |||
| * | |||
| * @param url The new Url value | |||
| */ | |||
| public void setUrl( String url ) | |||
| { | |||
| this.url = url; | |||
| } | |||
| /** | |||
| * Set the user name for the DB connection. | |||
| * | |||
| * @param userId The new Userid value | |||
| */ | |||
| public void setUserid( String userId ) | |||
| { | |||
| this.userId = userId; | |||
| } | |||
| /** | |||
| * Set the version required | |||
| * | |||
| * @param version The new Version value | |||
| */ | |||
| public void setVersion( String version ) | |||
| { | |||
| this.version = version.toLowerCase(); | |||
| } | |||
| /** | |||
| * Adds a set of files (nested fileset attribute). | |||
| * | |||
| * @param set The feature to be added to the Fileset attribute | |||
| */ | |||
| public void addFileset( FileSet set ) | |||
| { | |||
| filesets.addElement( set ); | |||
| } | |||
| /** | |||
| * Set the sql command to execute | |||
| * | |||
| * @param sql The feature to be added to the Text attribute | |||
| */ | |||
| public void addText( String sql ) | |||
| { | |||
| this.sqlCommand += sql; | |||
| } | |||
| /** | |||
| * Create the classpath for loading the driver. | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public Path createClasspath() | |||
| { | |||
| if( this.classpath == null ) | |||
| { | |||
| this.classpath = new Path( project ); | |||
| } | |||
| return this.classpath.createPath(); | |||
| } | |||
| /** | |||
| * Set the sql command to execute | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public Transaction createTransaction() | |||
| { | |||
| Transaction t = new Transaction(); | |||
| transactions.addElement( t ); | |||
| return t; | |||
| } | |||
| /** | |||
| * Load the sql file and then execute it | |||
| * | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| sqlCommand = sqlCommand.trim(); | |||
| if( srcFile == null && sqlCommand.length() == 0 && filesets.isEmpty() ) | |||
| { | |||
| if( transactions.size() == 0 ) | |||
| { | |||
| throw new BuildException( "Source file or fileset, transactions or sql statement must be set!", location ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| // deal with the filesets | |||
| for( int i = 0; i < filesets.size(); i++ ) | |||
| { | |||
| FileSet fs = ( FileSet )filesets.elementAt( i ); | |||
| DirectoryScanner ds = fs.getDirectoryScanner( project ); | |||
| File srcDir = fs.getDir( project ); | |||
| String[] srcFiles = ds.getIncludedFiles(); | |||
| // Make a transaction for each file | |||
| for( int j = 0; j < srcFiles.length; j++ ) | |||
| { | |||
| Transaction t = createTransaction(); | |||
| t.setSrc( new File( srcDir, srcFiles[j] ) ); | |||
| } | |||
| } | |||
| // Make a transaction group for the outer command | |||
| Transaction t = createTransaction(); | |||
| t.setSrc( srcFile ); | |||
| t.addText( sqlCommand ); | |||
| } | |||
| if( driver == null ) | |||
| { | |||
| throw new BuildException( "Driver attribute must be set!", location ); | |||
| } | |||
| if( userId == null ) | |||
| { | |||
| throw new BuildException( "User Id attribute must be set!", location ); | |||
| } | |||
| if( password == null ) | |||
| { | |||
| throw new BuildException( "Password attribute must be set!", location ); | |||
| } | |||
| if( url == null ) | |||
| { | |||
| throw new BuildException( "Url attribute must be set!", location ); | |||
| } | |||
| if( srcFile != null && !srcFile.exists() ) | |||
| { | |||
| throw new BuildException( "Source file does not exist!", location ); | |||
| } | |||
| Driver driverInstance = null; | |||
| // Load the driver using the | |||
| try | |||
| { | |||
| Class dc; | |||
| if( classpath != null ) | |||
| { | |||
| log( "Loading " + driver + " using AntClassLoader with classpath " + classpath, | |||
| Project.MSG_VERBOSE ); | |||
| loader = new AntClassLoader( project, classpath ); | |||
| dc = loader.loadClass( driver ); | |||
| } | |||
| else | |||
| { | |||
| log( "Loading " + driver + " using system loader.", Project.MSG_VERBOSE ); | |||
| dc = Class.forName( driver ); | |||
| } | |||
| driverInstance = ( Driver )dc.newInstance(); | |||
| } | |||
| catch( ClassNotFoundException e ) | |||
| { | |||
| throw new BuildException( "Class Not Found: JDBC driver " + driver + " could not be loaded", location ); | |||
| } | |||
| catch( IllegalAccessException e ) | |||
| { | |||
| throw new BuildException( "Illegal Access: JDBC driver " + driver + " could not be loaded", location ); | |||
| } | |||
| catch( InstantiationException e ) | |||
| { | |||
| throw new BuildException( "Instantiation Exception: JDBC driver " + driver + " could not be loaded", location ); | |||
| } | |||
| try | |||
| { | |||
| log( "connecting to " + url, Project.MSG_VERBOSE ); | |||
| Properties info = new Properties(); | |||
| info.put( "user", userId ); | |||
| info.put( "password", password ); | |||
| conn = driverInstance.connect( url, info ); | |||
| if( conn == null ) | |||
| { | |||
| // Driver doesn't understand the URL | |||
| throw new SQLException( "No suitable Driver for " + url ); | |||
| } | |||
| if( !isValidRdbms( conn ) ) | |||
| return; | |||
| conn.setAutoCommit( autocommit ); | |||
| statement = conn.createStatement(); | |||
| PrintStream out = System.out; | |||
| try | |||
| { | |||
| if( output != null ) | |||
| { | |||
| log( "Opening PrintStream to output file " + output, Project.MSG_VERBOSE ); | |||
| out = new PrintStream( new BufferedOutputStream( new FileOutputStream( output ) ) ); | |||
| } | |||
| // Process all transactions | |||
| for( Enumeration e = transactions.elements(); | |||
| e.hasMoreElements(); ) | |||
| { | |||
| ( ( Transaction )e.nextElement() ).runTransaction( out ); | |||
| if( !autocommit ) | |||
| { | |||
| log( "Commiting transaction", Project.MSG_VERBOSE ); | |||
| conn.commit(); | |||
| } | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| if( out != null && out != System.out ) | |||
| { | |||
| out.close(); | |||
| } | |||
| } | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| if( !autocommit && conn != null && onError.equals( "abort" ) ) | |||
| { | |||
| try | |||
| { | |||
| conn.rollback(); | |||
| } | |||
| catch( SQLException ex ) | |||
| {} | |||
| } | |||
| throw new BuildException( e ); | |||
| } | |||
| catch( SQLException e ) | |||
| { | |||
| if( !autocommit && conn != null && onError.equals( "abort" ) ) | |||
| { | |||
| try | |||
| { | |||
| conn.rollback(); | |||
| } | |||
| catch( SQLException ex ) | |||
| {} | |||
| } | |||
| throw new BuildException( e ); | |||
| } | |||
| finally | |||
| { | |||
| try | |||
| { | |||
| if( statement != null ) | |||
| { | |||
| statement.close(); | |||
| } | |||
| if( conn != null ) | |||
| { | |||
| conn.close(); | |||
| } | |||
| } | |||
| catch( SQLException e ) | |||
| {} | |||
| } | |||
| log( goodSql + " of " + totalSql + | |||
| " SQL statements executed successfully" ); | |||
| } | |||
| /** | |||
| * Verify if connected to the correct RDBMS | |||
| * | |||
| * @param conn Description of Parameter | |||
| * @return The ValidRdbms value | |||
| */ | |||
| protected boolean isValidRdbms( Connection conn ) | |||
| { | |||
| if( rdbms == null && version == null ) | |||
| return true; | |||
| try | |||
| { | |||
| DatabaseMetaData dmd = conn.getMetaData(); | |||
| if( rdbms != null ) | |||
| { | |||
| String theVendor = dmd.getDatabaseProductName().toLowerCase(); | |||
| log( "RDBMS = " + theVendor, Project.MSG_VERBOSE ); | |||
| if( theVendor == null || theVendor.indexOf( rdbms ) < 0 ) | |||
| { | |||
| log( "Not the required RDBMS: " + rdbms, Project.MSG_VERBOSE ); | |||
| return false; | |||
| } | |||
| } | |||
| if( version != null ) | |||
| { | |||
| String theVersion = dmd.getDatabaseProductVersion().toLowerCase(); | |||
| log( "Version = " + theVersion, Project.MSG_VERBOSE ); | |||
| if( theVersion == null || | |||
| !( theVersion.startsWith( version ) || | |||
| theVersion.indexOf( " " + version ) >= 0 ) ) | |||
| { | |||
| log( "Not the required version: \"" + version + "\"", Project.MSG_VERBOSE ); | |||
| return false; | |||
| } | |||
| } | |||
| } | |||
| catch( SQLException e ) | |||
| { | |||
| // Could not get the required information | |||
| log( "Failed to obtain required RDBMS information", Project.MSG_ERR ); | |||
| return false; | |||
| } | |||
| return true; | |||
| } | |||
| /** | |||
| * Exec the sql statement. | |||
| * | |||
| * @param sql Description of Parameter | |||
| * @param out Description of Parameter | |||
| * @exception SQLException Description of Exception | |||
| */ | |||
| protected void execSQL( String sql, PrintStream out ) | |||
| throws SQLException | |||
| { | |||
| // Check and ignore empty statements | |||
| if( "".equals( sql.trim() ) ) | |||
| return; | |||
| try | |||
| { | |||
| totalSql++; | |||
| if( !statement.execute( sql ) ) | |||
| { | |||
| log( statement.getUpdateCount() + " rows affected", | |||
| Project.MSG_VERBOSE ); | |||
| } | |||
| else | |||
| { | |||
| if( print ) | |||
| { | |||
| printResults( out ); | |||
| } | |||
| } | |||
| SQLWarning warning = conn.getWarnings(); | |||
| while( warning != null ) | |||
| { | |||
| log( warning + " sql warning", Project.MSG_VERBOSE ); | |||
| warning = warning.getNextWarning(); | |||
| } | |||
| conn.clearWarnings(); | |||
| goodSql++; | |||
| } | |||
| catch( SQLException e ) | |||
| { | |||
| log( "Failed to execute: " + sql, Project.MSG_ERR ); | |||
| if( !onError.equals( "continue" ) ) | |||
| throw e; | |||
| log( e.toString(), Project.MSG_ERR ); | |||
| } | |||
| } | |||
| /** | |||
| * print any results in the statement. | |||
| * | |||
| * @param out Description of Parameter | |||
| * @exception java.sql.SQLException Description of Exception | |||
| */ | |||
| protected void printResults( PrintStream out ) | |||
| throws java.sql.SQLException | |||
| { | |||
| ResultSet rs = null; | |||
| do | |||
| { | |||
| rs = statement.getResultSet(); | |||
| if( rs != null ) | |||
| { | |||
| log( "Processing new result set.", Project.MSG_VERBOSE ); | |||
| ResultSetMetaData md = rs.getMetaData(); | |||
| int columnCount = md.getColumnCount(); | |||
| StringBuffer line = new StringBuffer(); | |||
| if( showheaders ) | |||
| { | |||
| for( int col = 1; col < columnCount; col++ ) | |||
| { | |||
| line.append( md.getColumnName( col ) ); | |||
| line.append( "," ); | |||
| } | |||
| line.append( md.getColumnName( columnCount ) ); | |||
| out.println( line ); | |||
| line.setLength( 0 ); | |||
| } | |||
| while( rs.next() ) | |||
| { | |||
| boolean first = true; | |||
| for( int col = 1; col <= columnCount; col++ ) | |||
| { | |||
| String columnValue = rs.getString( col ); | |||
| if( columnValue != null ) | |||
| { | |||
| columnValue = columnValue.trim(); | |||
| } | |||
| if( first ) | |||
| { | |||
| first = false; | |||
| } | |||
| else | |||
| { | |||
| line.append( "," ); | |||
| } | |||
| line.append( columnValue ); | |||
| } | |||
| out.println( line ); | |||
| line.setLength( 0 ); | |||
| } | |||
| } | |||
| }while ( statement.getMoreResults() ); | |||
| out.println(); | |||
| } | |||
| protected void runStatements( Reader reader, PrintStream out ) | |||
| throws SQLException, IOException | |||
| { | |||
| String sql = ""; | |||
| String line = ""; | |||
| BufferedReader in = new BufferedReader( reader ); | |||
| try | |||
| { | |||
| while( ( line = in.readLine() ) != null ) | |||
| { | |||
| line = line.trim(); | |||
| line = project.replaceProperties( line ); | |||
| if( line.startsWith( "//" ) ) | |||
| continue; | |||
| if( line.startsWith( "--" ) ) | |||
| continue; | |||
| StringTokenizer st = new StringTokenizer( line ); | |||
| if( st.hasMoreTokens() ) | |||
| { | |||
| String token = st.nextToken(); | |||
| if( "REM".equalsIgnoreCase( token ) ) | |||
| { | |||
| continue; | |||
| } | |||
| } | |||
| sql += " " + line; | |||
| sql = sql.trim(); | |||
| // SQL defines "--" as a comment to EOL | |||
| // and in Oracle it may contain a hint | |||
| // so we cannot just remove it, instead we must end it | |||
| if( line.indexOf( "--" ) >= 0 ) | |||
| sql += "\n"; | |||
| if( delimiterType.equals( DelimiterType.NORMAL ) && sql.endsWith( delimiter ) || | |||
| delimiterType.equals( DelimiterType.ROW ) && line.equals( delimiter ) ) | |||
| { | |||
| log( "SQL: " + sql, Project.MSG_VERBOSE ); | |||
| execSQL( sql.substring( 0, sql.length() - delimiter.length() ), out ); | |||
| sql = ""; | |||
| } | |||
| } | |||
| // Catch any statements not followed by ; | |||
| if( !sql.equals( "" ) ) | |||
| { | |||
| execSQL( sql, out ); | |||
| } | |||
| } | |||
| catch( SQLException e ) | |||
| { | |||
| throw e; | |||
| } | |||
| } | |||
| public static class DelimiterType extends EnumeratedAttribute | |||
| { | |||
| public final static String NORMAL = "normal"; | |||
| public final static String ROW = "row"; | |||
| public String[] getValues() | |||
| { | |||
| return new String[]{NORMAL, ROW}; | |||
| } | |||
| } | |||
| /** | |||
| * Enumerated attribute with the values "continue", "stop" and "abort" for | |||
| * the onerror attribute. | |||
| * | |||
| * @author RT | |||
| */ | |||
| public static class OnError extends EnumeratedAttribute | |||
| { | |||
| public String[] getValues() | |||
| { | |||
| return new String[]{"continue", "stop", "abort"}; | |||
| } | |||
| } | |||
| /** | |||
| * Contains the definition of a new transaction element. Transactions allow | |||
| * several files or blocks of statements to be executed using the same JDBC | |||
| * connection and commit operation in between. | |||
| * | |||
| * @author RT | |||
| */ | |||
| public class Transaction | |||
| { | |||
| private File tSrcFile = null; | |||
| private String tSqlCommand = ""; | |||
| public void setSrc( File src ) | |||
| { | |||
| this.tSrcFile = src; | |||
| } | |||
| public void addText( String sql ) | |||
| { | |||
| this.tSqlCommand += sql; | |||
| } | |||
| private void runTransaction( PrintStream out ) | |||
| throws IOException, SQLException | |||
| { | |||
| if( tSqlCommand.length() != 0 ) | |||
| { | |||
| log( "Executing commands", Project.MSG_INFO ); | |||
| runStatements( new StringReader( tSqlCommand ), out ); | |||
| } | |||
| if( tSrcFile != null ) | |||
| { | |||
| log( "Executing file: " + tSrcFile.getAbsolutePath(), | |||
| Project.MSG_INFO ); | |||
| Reader reader = ( encoding == null ) ? new FileReader( tSrcFile ) | |||
| : new InputStreamReader( new FileInputStream( tSrcFile ), encoding ); | |||
| runStatements( reader, out ); | |||
| reader.close(); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,406 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.BufferedInputStream; | |||
| import java.io.File; | |||
| import java.io.FileInputStream; | |||
| import java.io.IOException; | |||
| import java.io.PrintStream; | |||
| import java.util.Enumeration; | |||
| import java.util.StringTokenizer; | |||
| import java.util.Vector; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.Task; | |||
| import org.apache.tools.mail.MailMessage; | |||
| /** | |||
| * A task to send SMTP email. <p> | |||
| * | |||
| * | |||
| * <tableborder="1" cellpadding="3" cellspacing="0"> | |||
| * | |||
| * <trbgcolor="#CCCCFF"> | |||
| * | |||
| * <th> | |||
| * Attribute | |||
| * </th> | |||
| * | |||
| * <th> | |||
| * Description | |||
| * </th> | |||
| * | |||
| * <th> | |||
| * Required | |||
| * </th> | |||
| * | |||
| * </tr> | |||
| * | |||
| * <tr> | |||
| * | |||
| * <td> | |||
| * from | |||
| * </td> | |||
| * | |||
| * <td> | |||
| * Email address of sender. | |||
| * </td> | |||
| * | |||
| * <td> | |||
| * Yes | |||
| * </td> | |||
| * | |||
| * </tr> | |||
| * | |||
| * <tr> | |||
| * | |||
| * <td> | |||
| * mailhost | |||
| * </td> | |||
| * | |||
| * <td> | |||
| * Host name of the mail server. | |||
| * </td> | |||
| * | |||
| * <td> | |||
| * No, default to "localhost" | |||
| * </td> | |||
| * | |||
| * </tr> | |||
| * | |||
| * <tr> | |||
| * | |||
| * <td> | |||
| * toList | |||
| * </td> | |||
| * | |||
| * <td> | |||
| * Comma-separated list of recipients. | |||
| * </td> | |||
| * | |||
| * <td> | |||
| * Yes | |||
| * </td> | |||
| * | |||
| * </tr> | |||
| * | |||
| * <tr> | |||
| * | |||
| * <td> | |||
| * subject | |||
| * </td> | |||
| * | |||
| * <td> | |||
| * Email subject line. | |||
| * </td> | |||
| * | |||
| * <td> | |||
| * No | |||
| * </td> | |||
| * | |||
| * </tr> | |||
| * | |||
| * <tr> | |||
| * | |||
| * <td> | |||
| * files | |||
| * </td> | |||
| * | |||
| * <td> | |||
| * Filename(s) of text to send in the body of the email. Multiple files | |||
| * are comma-separated. | |||
| * </td> | |||
| * | |||
| * <tdrowspan="2"> | |||
| * One of these two attributes | |||
| * </td> | |||
| * | |||
| * </tr> | |||
| * | |||
| * <tr> | |||
| * | |||
| * <td> | |||
| * message | |||
| * </td> | |||
| * | |||
| * <td> | |||
| * Message to send inthe body of the email. | |||
| * </td> | |||
| * | |||
| * </tr> | |||
| * | |||
| * </table> | |||
| * | |||
| * <tr> | |||
| * | |||
| * <td> | |||
| * includefilenames | |||
| * </td> | |||
| * | |||
| * <td> | |||
| * Includes filenames before file contents when set to true. | |||
| * </td> | |||
| * | |||
| * <td> | |||
| * No, default is <I>false</I> | |||
| * </td> | |||
| * | |||
| * </tr> | |||
| * <p> | |||
| * | |||
| * | |||
| * | |||
| * @author glenn_twiggs@bmc.com | |||
| * @author <a href="mailto:umagesh@rediffmail.com">Magesh Umasankar</a> | |||
| */ | |||
| public class SendEmail extends Task | |||
| { | |||
| private String mailhost = "localhost"; | |||
| private int mailport = MailMessage.DEFAULT_PORT; | |||
| private Vector files = new Vector(); | |||
| /** | |||
| * failure flag | |||
| */ | |||
| private boolean failOnError = true; | |||
| private String from; | |||
| private boolean includefilenames; | |||
| private String message; | |||
| private String subject; | |||
| private String toList; | |||
| /** | |||
| * Creates new SendEmail | |||
| */ | |||
| public SendEmail() { } | |||
| /** | |||
| * Sets the FailOnError attribute of the MimeMail object | |||
| * | |||
| * @param failOnError The new FailOnError value | |||
| * @since 1.5 | |||
| */ | |||
| public void setFailOnError( boolean failOnError ) | |||
| { | |||
| this.failOnError = failOnError; | |||
| } | |||
| /** | |||
| * Sets the file parameter of this build task. | |||
| * | |||
| * @param filenames Filenames to include as the message body of this email. | |||
| */ | |||
| public void setFiles( String filenames ) | |||
| { | |||
| StringTokenizer t = new StringTokenizer( filenames, ", " ); | |||
| while( t.hasMoreTokens() ) | |||
| { | |||
| files.addElement( project.resolveFile( t.nextToken() ) ); | |||
| } | |||
| } | |||
| /** | |||
| * Sets the from parameter of this build task. | |||
| * | |||
| * @param from Email address of sender. | |||
| */ | |||
| public void setFrom( String from ) | |||
| { | |||
| this.from = from; | |||
| } | |||
| /** | |||
| * Sets Includefilenames attribute | |||
| * | |||
| * @param includefilenames Set to true if file names are to be included. | |||
| * @since 1.5 | |||
| */ | |||
| public void setIncludefilenames( boolean includefilenames ) | |||
| { | |||
| this.includefilenames = includefilenames; | |||
| } | |||
| /** | |||
| * Sets the mailhost parameter of this build task. | |||
| * | |||
| * @param mailhost Mail host name. | |||
| */ | |||
| public void setMailhost( String mailhost ) | |||
| { | |||
| this.mailhost = mailhost; | |||
| } | |||
| /** | |||
| * Sets the mailport parameter of this build task. | |||
| * | |||
| * @param value mail port name. | |||
| */ | |||
| public void setMailport( Integer value ) | |||
| { | |||
| this.mailport = value.intValue(); | |||
| } | |||
| /** | |||
| * Sets the message parameter of this build task. | |||
| * | |||
| * @param message Message body of this email. | |||
| */ | |||
| public void setMessage( String message ) | |||
| { | |||
| this.message = message; | |||
| } | |||
| /** | |||
| * Sets the subject parameter of this build task. | |||
| * | |||
| * @param subject Subject of this email. | |||
| */ | |||
| public void setSubject( String subject ) | |||
| { | |||
| this.subject = subject; | |||
| } | |||
| /** | |||
| * Sets the toList parameter of this build task. | |||
| * | |||
| * @param toList Comma-separated list of email recipient addreses. | |||
| */ | |||
| public void setToList( String toList ) | |||
| { | |||
| this.toList = toList; | |||
| } | |||
| /** | |||
| * Executes this build task. | |||
| * | |||
| * @throws BuildException if there is an error during task execution. | |||
| */ | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| try | |||
| { | |||
| MailMessage mailMessage = new MailMessage( mailhost ); | |||
| mailMessage.setPort( mailport ); | |||
| if( from != null ) | |||
| { | |||
| mailMessage.from( from ); | |||
| } | |||
| else | |||
| { | |||
| throw new BuildException( "Attribute \"from\" is required." ); | |||
| } | |||
| if( toList != null ) | |||
| { | |||
| StringTokenizer t = new StringTokenizer( toList, ", ", false ); | |||
| while( t.hasMoreTokens() ) | |||
| { | |||
| mailMessage.to( t.nextToken() ); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| throw new BuildException( "Attribute \"toList\" is required." ); | |||
| } | |||
| if( subject != null ) | |||
| { | |||
| mailMessage.setSubject( subject ); | |||
| } | |||
| if( !files.isEmpty() ) | |||
| { | |||
| PrintStream out = mailMessage.getPrintStream(); | |||
| for( Enumeration e = files.elements(); e.hasMoreElements(); ) | |||
| { | |||
| File file = ( File )e.nextElement(); | |||
| if( file.exists() && file.canRead() ) | |||
| { | |||
| int bufsize = 1024; | |||
| int length; | |||
| byte[] buf = new byte[bufsize]; | |||
| if( includefilenames ) | |||
| { | |||
| String filename = file.getName(); | |||
| int filenamelength = filename.length(); | |||
| out.println( filename ); | |||
| for( int star = 0; star < filenamelength; star++ ) | |||
| { | |||
| out.print( '=' ); | |||
| } | |||
| out.println(); | |||
| } | |||
| BufferedInputStream in = null; | |||
| try | |||
| { | |||
| in = new BufferedInputStream( | |||
| new FileInputStream( file ), bufsize ); | |||
| while( ( length = in.read( buf, 0, bufsize ) ) != -1 ) | |||
| { | |||
| out.write( buf, 0, length ); | |||
| } | |||
| if( includefilenames ) | |||
| { | |||
| out.println(); | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| if( in != null ) | |||
| { | |||
| try | |||
| { | |||
| in.close(); | |||
| } | |||
| catch( IOException ioe ) | |||
| {} | |||
| } | |||
| } | |||
| } | |||
| else | |||
| { | |||
| throw new BuildException( "File \"" + file.getName() | |||
| + "\" does not exist or is not readable." ); | |||
| } | |||
| } | |||
| } | |||
| else if( message != null ) | |||
| { | |||
| PrintStream out = mailMessage.getPrintStream(); | |||
| out.print( message ); | |||
| } | |||
| else | |||
| { | |||
| throw new BuildException( "Attribute \"file\" or \"message\" is required." ); | |||
| } | |||
| log( "Sending email" ); | |||
| mailMessage.sendAndClose(); | |||
| } | |||
| catch( IOException ioe ) | |||
| { | |||
| String err = "IO error sending mail " + ioe.toString(); | |||
| if( failOnError ) | |||
| { | |||
| throw new BuildException( err, ioe, location ); | |||
| } | |||
| else | |||
| { | |||
| log( err, Project.MSG_ERR ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,60 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.util.Enumeration; | |||
| import java.util.Vector; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Task; | |||
| import org.apache.tools.ant.TaskContainer; | |||
| /** | |||
| * Implements a single threaded task execution. <p> | |||
| * | |||
| * | |||
| * | |||
| * @author Thomas Christen <a href="mailto:chr@active.ch">chr@active.ch</a> | |||
| */ | |||
| public class Sequential extends Task | |||
| implements TaskContainer | |||
| { | |||
| /** | |||
| * Optional Vector holding the nested tasks | |||
| */ | |||
| private Vector nestedTasks = new Vector(); | |||
| /** | |||
| * Add a nested task to Sequential. <p> | |||
| * | |||
| * | |||
| * | |||
| * @param nestedTask Nested task to execute Sequential <p> | |||
| * | |||
| * | |||
| */ | |||
| public void addTask( Task nestedTask ) | |||
| { | |||
| nestedTasks.addElement( nestedTask ); | |||
| } | |||
| /** | |||
| * Execute all nestedTasks. | |||
| * | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| for( Enumeration e = nestedTasks.elements(); e.hasMoreElements(); ) | |||
| { | |||
| Task nestedTask = ( Task )e.nextElement(); | |||
| nestedTask.perform(); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,335 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| import java.util.Enumeration; | |||
| import java.util.Vector; | |||
| import java.util.zip.ZipEntry; | |||
| import java.util.zip.ZipFile; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.DirectoryScanner; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.Task; | |||
| import org.apache.tools.ant.types.FileSet; | |||
| /** | |||
| * Sign a archive. | |||
| * | |||
| * @author Peter Donald <a href="mailto:donaldp@apache.org">donaldp@apache.org | |||
| * </a> | |||
| * @author Nick Fortescue <a href="mailto:nick@ox.compsoc.net"> | |||
| * nick@ox.compsoc.net</a> | |||
| */ | |||
| public class SignJar extends Task | |||
| { | |||
| /** | |||
| * the filesets of the jars to sign | |||
| */ | |||
| protected Vector filesets = new Vector(); | |||
| /** | |||
| * The alias of signer. | |||
| */ | |||
| protected String alias; | |||
| protected boolean internalsf; | |||
| /** | |||
| * The name of the jar file. | |||
| */ | |||
| protected File jar; | |||
| protected String keypass; | |||
| /** | |||
| * The name of keystore file. | |||
| */ | |||
| protected File keystore; | |||
| /** | |||
| * Whether to assume a jar which has an appropriate .SF file in is already | |||
| * signed. | |||
| */ | |||
| protected boolean lazy; | |||
| protected boolean sectionsonly; | |||
| protected File sigfile; | |||
| protected File signedjar; | |||
| protected String storepass; | |||
| protected String storetype; | |||
| protected boolean verbose; | |||
| public void setAlias( final String alias ) | |||
| { | |||
| this.alias = alias; | |||
| } | |||
| public void setInternalsf( final boolean internalsf ) | |||
| { | |||
| this.internalsf = internalsf; | |||
| } | |||
| public void setJar( final File jar ) | |||
| { | |||
| this.jar = jar; | |||
| } | |||
| public void setKeypass( final String keypass ) | |||
| { | |||
| this.keypass = keypass; | |||
| } | |||
| public void setKeystore( final File keystore ) | |||
| { | |||
| this.keystore = keystore; | |||
| } | |||
| public void setLazy( final boolean lazy ) | |||
| { | |||
| this.lazy = lazy; | |||
| } | |||
| public void setSectionsonly( final boolean sectionsonly ) | |||
| { | |||
| this.sectionsonly = sectionsonly; | |||
| } | |||
| public void setSigfile( final File sigfile ) | |||
| { | |||
| this.sigfile = sigfile; | |||
| } | |||
| public void setSignedjar( final File signedjar ) | |||
| { | |||
| this.signedjar = signedjar; | |||
| } | |||
| public void setStorepass( final String storepass ) | |||
| { | |||
| this.storepass = storepass; | |||
| } | |||
| public void setStoretype( final String storetype ) | |||
| { | |||
| this.storetype = storetype; | |||
| } | |||
| public void setVerbose( final boolean verbose ) | |||
| { | |||
| this.verbose = verbose; | |||
| } | |||
| /** | |||
| * Adds a set of files (nested fileset attribute). | |||
| * | |||
| * @param set The feature to be added to the Fileset attribute | |||
| */ | |||
| public void addFileset( final FileSet set ) | |||
| { | |||
| filesets.addElement( set ); | |||
| } | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| if( null == jar && null == filesets ) | |||
| { | |||
| throw new BuildException( "jar must be set through jar attribute or nested filesets" ); | |||
| } | |||
| if( null != jar ) | |||
| { | |||
| doOneJar( jar, signedjar ); | |||
| return; | |||
| } | |||
| else | |||
| { | |||
| //Assume null != filesets | |||
| // deal with the filesets | |||
| for( int i = 0; i < filesets.size(); i++ ) | |||
| { | |||
| FileSet fs = ( FileSet )filesets.elementAt( i ); | |||
| DirectoryScanner ds = fs.getDirectoryScanner( project ); | |||
| String[] jarFiles = ds.getIncludedFiles(); | |||
| for( int j = 0; j < jarFiles.length; j++ ) | |||
| { | |||
| doOneJar( new File( fs.getDir( project ), jarFiles[j] ), null ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| protected boolean isSigned( File file ) | |||
| { | |||
| final String SIG_START = "META-INF/"; | |||
| final String SIG_END = ".SF"; | |||
| if( !file.exists() ) | |||
| { | |||
| return false; | |||
| } | |||
| ZipFile jarFile = null; | |||
| try | |||
| { | |||
| jarFile = new ZipFile( file ); | |||
| if( null == alias ) | |||
| { | |||
| Enumeration entries = jarFile.entries(); | |||
| while( entries.hasMoreElements() ) | |||
| { | |||
| String name = ( ( ZipEntry )entries.nextElement() ).getName(); | |||
| if( name.startsWith( SIG_START ) && name.endsWith( SIG_END ) ) | |||
| { | |||
| return true; | |||
| } | |||
| } | |||
| return false; | |||
| } | |||
| else | |||
| { | |||
| return jarFile.getEntry( SIG_START + alias.toUpperCase() + | |||
| SIG_END ) != null; | |||
| } | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| return false; | |||
| } | |||
| finally | |||
| { | |||
| if( jarFile != null ) | |||
| { | |||
| try | |||
| { | |||
| jarFile.close(); | |||
| } | |||
| catch( IOException e ) | |||
| {} | |||
| } | |||
| } | |||
| } | |||
| protected boolean isUpToDate( File jarFile, File signedjarFile ) | |||
| { | |||
| if( null == jarFile ) | |||
| { | |||
| return false; | |||
| } | |||
| if( null != signedjarFile ) | |||
| { | |||
| if( !jarFile.exists() ) | |||
| return false; | |||
| if( !signedjarFile.exists() ) | |||
| return false; | |||
| if( jarFile.equals( signedjarFile ) ) | |||
| return false; | |||
| if( signedjarFile.lastModified() > jarFile.lastModified() ) | |||
| return true; | |||
| } | |||
| else | |||
| { | |||
| if( lazy ) | |||
| { | |||
| return isSigned( jarFile ); | |||
| } | |||
| } | |||
| return false; | |||
| } | |||
| private void doOneJar( File jarSource, File jarTarget ) | |||
| throws BuildException | |||
| { | |||
| if( project.getJavaVersion().equals( Project.JAVA_1_1 ) ) | |||
| { | |||
| throw new BuildException( "The signjar task is only available on JDK versions 1.2 or greater" ); | |||
| } | |||
| if( null == alias ) | |||
| { | |||
| throw new BuildException( "alias attribute must be set" ); | |||
| } | |||
| if( null == storepass ) | |||
| { | |||
| throw new BuildException( "storepass attribute must be set" ); | |||
| } | |||
| if( isUpToDate( jarSource, jarTarget ) ) | |||
| return; | |||
| final StringBuffer sb = new StringBuffer(); | |||
| final ExecTask cmd = ( ExecTask )project.createTask( "exec" ); | |||
| cmd.setExecutable( "jarsigner" ); | |||
| if( null != keystore ) | |||
| { | |||
| cmd.createArg().setValue( "-keystore" ); | |||
| cmd.createArg().setValue( keystore.toString() ); | |||
| } | |||
| if( null != storepass ) | |||
| { | |||
| cmd.createArg().setValue( "-storepass" ); | |||
| cmd.createArg().setValue( storepass ); | |||
| } | |||
| if( null != storetype ) | |||
| { | |||
| cmd.createArg().setValue( "-storetype" ); | |||
| cmd.createArg().setValue( storetype ); | |||
| } | |||
| if( null != keypass ) | |||
| { | |||
| cmd.createArg().setValue( "-keypass" ); | |||
| cmd.createArg().setValue( keypass ); | |||
| } | |||
| if( null != sigfile ) | |||
| { | |||
| cmd.createArg().setValue( "-sigfile" ); | |||
| cmd.createArg().setValue( sigfile.toString() ); | |||
| } | |||
| if( null != jarTarget ) | |||
| { | |||
| cmd.createArg().setValue( "-signedjar" ); | |||
| cmd.createArg().setValue( jarTarget.toString() ); | |||
| } | |||
| if( verbose ) | |||
| { | |||
| cmd.createArg().setValue( "-verbose" ); | |||
| } | |||
| if( internalsf ) | |||
| { | |||
| cmd.createArg().setValue( "-internalsf" ); | |||
| } | |||
| if( sectionsonly ) | |||
| { | |||
| cmd.createArg().setValue( "-sectionsonly" ); | |||
| } | |||
| cmd.createArg().setValue( jarSource.toString() ); | |||
| cmd.createArg().setValue( alias ); | |||
| log( "Signing Jar : " + jarSource.getAbsolutePath() ); | |||
| cmd.setFailonerror( true ); | |||
| cmd.setTaskName( getTaskName() ); | |||
| cmd.execute(); | |||
| } | |||
| } | |||
| @@ -0,0 +1,183 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.Task; | |||
| /** | |||
| * A task to sleep for a period of time | |||
| * | |||
| * @author steve_l@iseran.com steve loughran | |||
| * @created 01 May 2001 | |||
| */ | |||
| public class Sleep extends Task | |||
| { | |||
| /** | |||
| * failure flag | |||
| */ | |||
| private boolean failOnError = true; | |||
| /** | |||
| * Description of the Field | |||
| */ | |||
| private int seconds = 0; | |||
| /** | |||
| * Description of the Field | |||
| */ | |||
| private int hours = 0; | |||
| /** | |||
| * Description of the Field | |||
| */ | |||
| private int minutes = 0; | |||
| /** | |||
| * Description of the Field | |||
| */ | |||
| private int milliseconds = 0; | |||
| /** | |||
| * Creates new instance | |||
| */ | |||
| public Sleep() { } | |||
| /** | |||
| * Sets the FailOnError attribute of the MimeMail object | |||
| * | |||
| * @param failOnError The new FailOnError value | |||
| */ | |||
| public void setFailOnError( boolean failOnError ) | |||
| { | |||
| this.failOnError = failOnError; | |||
| } | |||
| /** | |||
| * Sets the Hours attribute of the Sleep object | |||
| * | |||
| * @param hours The new Hours value | |||
| */ | |||
| public void setHours( int hours ) | |||
| { | |||
| this.hours = hours; | |||
| } | |||
| /** | |||
| * Sets the Milliseconds attribute of the Sleep object | |||
| * | |||
| * @param milliseconds The new Milliseconds value | |||
| */ | |||
| public void setMilliseconds( int milliseconds ) | |||
| { | |||
| this.milliseconds = milliseconds; | |||
| } | |||
| /** | |||
| * Sets the Minutes attribute of the Sleep object | |||
| * | |||
| * @param minutes The new Minutes value | |||
| */ | |||
| public void setMinutes( int minutes ) | |||
| { | |||
| this.minutes = minutes; | |||
| } | |||
| /** | |||
| * Sets the Seconds attribute of the Sleep object | |||
| * | |||
| * @param seconds The new Seconds value | |||
| */ | |||
| public void setSeconds( int seconds ) | |||
| { | |||
| this.seconds = seconds; | |||
| } | |||
| /** | |||
| * sleep for a period of time | |||
| * | |||
| * @param millis time to sleep | |||
| */ | |||
| public void doSleep( long millis ) | |||
| { | |||
| try | |||
| { | |||
| Thread.currentThread().sleep( millis ); | |||
| } | |||
| catch( InterruptedException ie ) | |||
| { | |||
| } | |||
| } | |||
| /** | |||
| * Executes this build task. throws org.apache.tools.ant.BuildException if | |||
| * there is an error during task execution. | |||
| * | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| try | |||
| { | |||
| validate(); | |||
| long sleepTime = getSleepTime(); | |||
| log( "sleeping for " + sleepTime + " milliseconds", | |||
| Project.MSG_VERBOSE ); | |||
| doSleep( sleepTime ); | |||
| } | |||
| catch( Exception e ) | |||
| { | |||
| if( failOnError ) | |||
| { | |||
| throw new BuildException( e ); | |||
| } | |||
| else | |||
| { | |||
| String text = e.toString(); | |||
| log( text, Project.MSG_ERR ); | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * verify parameters | |||
| * | |||
| * @throws BuildException if something is invalid | |||
| */ | |||
| public void validate() | |||
| throws BuildException | |||
| { | |||
| long sleepTime = getSleepTime(); | |||
| if( getSleepTime() < 0 ) | |||
| { | |||
| throw new BuildException( "Negative sleep periods are not supported" ); | |||
| } | |||
| } | |||
| /** | |||
| * return time to sleep | |||
| * | |||
| * @return sleep time. if below 0 then there is an error | |||
| */ | |||
| private long getSleepTime() | |||
| { | |||
| return ( ( ( ( long )hours * 60 ) + minutes ) * 60 + seconds ) * 1000 + milliseconds; | |||
| } | |||
| } | |||
| @@ -0,0 +1,68 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.io.OutputStream; | |||
| /** | |||
| * Copies all data from an input stream to an output stream. | |||
| * | |||
| * @author thomas.haas@softwired-inc.com | |||
| */ | |||
| public class StreamPumper implements Runnable | |||
| { | |||
| // TODO: make SIZE and SLEEP instance variables. | |||
| // TODO: add a status flag to note if an error occured in run. | |||
| private final static int SLEEP = 5; | |||
| private final static int SIZE = 128; | |||
| private InputStream is; | |||
| private OutputStream os; | |||
| /** | |||
| * Create a new stream pumper. | |||
| * | |||
| * @param is input stream to read data from | |||
| * @param os output stream to write data to. | |||
| */ | |||
| public StreamPumper( InputStream is, OutputStream os ) | |||
| { | |||
| this.is = is; | |||
| this.os = os; | |||
| } | |||
| /** | |||
| * Copies data from the input stream to the output stream. Terminates as | |||
| * soon as the input stream is closed or an error occurs. | |||
| */ | |||
| public void run() | |||
| { | |||
| final byte[] buf = new byte[SIZE]; | |||
| int length; | |||
| try | |||
| { | |||
| while( ( length = is.read( buf ) ) > 0 ) | |||
| { | |||
| os.write( buf, 0, length ); | |||
| try | |||
| { | |||
| Thread.sleep( SLEEP ); | |||
| } | |||
| catch( InterruptedException e ) | |||
| {} | |||
| } | |||
| } | |||
| catch( IOException e ) | |||
| {} | |||
| } | |||
| } | |||
| @@ -0,0 +1,481 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.File; | |||
| import java.io.FileInputStream; | |||
| import java.io.FileOutputStream; | |||
| import java.io.IOException; | |||
| import java.util.Enumeration; | |||
| 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.types.EnumeratedAttribute; | |||
| import org.apache.tools.ant.types.FileSet; | |||
| import org.apache.tools.ant.util.MergingMapper; | |||
| import org.apache.tools.ant.util.SourceFileScanner; | |||
| import org.apache.tools.tar.TarConstants; | |||
| import org.apache.tools.tar.TarEntry; | |||
| import org.apache.tools.tar.TarOutputStream; | |||
| /** | |||
| * Creates a TAR archive. | |||
| * | |||
| * @author Stefano Mazzocchi <a href="mailto:stefano@apache.org"> | |||
| * stefano@apache.org</a> | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| * @author <a href="mailto:umagesh@apache.org">Magesh Umasankar</a> | |||
| */ | |||
| public class Tar extends MatchingTask | |||
| { | |||
| /** | |||
| * @deprecated Tar.WARN is deprecated and is replaced with | |||
| * Tar.TarLongFileMode.WARN | |||
| */ | |||
| public final static String WARN = "warn"; | |||
| /** | |||
| * @deprecated Tar.FAIL is deprecated and is replaced with | |||
| * Tar.TarLongFileMode.FAIL | |||
| */ | |||
| public final static String FAIL = "fail"; | |||
| /** | |||
| * @deprecated Tar.TRUNCATE is deprecated and is replaced with | |||
| * Tar.TarLongFileMode.TRUNCATE | |||
| */ | |||
| public final static String TRUNCATE = "truncate"; | |||
| /** | |||
| * @deprecated Tar.GNU is deprecated and is replaced with | |||
| * Tar.TarLongFileMode.GNU | |||
| */ | |||
| public final static String GNU = "gnu"; | |||
| /** | |||
| * @deprecated Tar.OMIT is deprecated and is replaced with | |||
| * Tar.TarLongFileMode.OMIT | |||
| */ | |||
| public final static String OMIT = "omit"; | |||
| private TarLongFileMode longFileMode = new TarLongFileMode(); | |||
| Vector filesets = new Vector(); | |||
| Vector fileSetFiles = new Vector(); | |||
| /** | |||
| * Indicates whether the user has been warned about long files already. | |||
| */ | |||
| private boolean longWarningGiven = false; | |||
| File baseDir; | |||
| File tarFile; | |||
| /** | |||
| * This is the base directory to look in for things to tar. | |||
| * | |||
| * @param baseDir The new Basedir value | |||
| */ | |||
| public void setBasedir( File baseDir ) | |||
| { | |||
| this.baseDir = baseDir; | |||
| } | |||
| /** | |||
| * Set how to handle long files. Allowable values are truncate - paths are | |||
| * truncated to the maximum length fail - paths greater than the maximim | |||
| * cause a build exception warn - paths greater than the maximum cause a | |||
| * warning and GNU is used gnu - GNU extensions are used for any paths | |||
| * greater than the maximum. omit - paths greater than the maximum are | |||
| * omitted from the archive | |||
| * | |||
| * @param mode The new Longfile value | |||
| * @deprecated setLongFile(String) is deprecated and is replaced with | |||
| * setLongFile(Tar.TarLongFileMode) to make Ant's Introspection | |||
| * mechanism do the work and also to encapsulate operations on the mode | |||
| * in its own class. | |||
| */ | |||
| public void setLongfile( String mode ) | |||
| { | |||
| log( "DEPRECATED - The setLongfile(String) method has been deprecated." | |||
| + " Use setLongfile(Tar.TarLongFileMode) instead." ); | |||
| this.longFileMode = new TarLongFileMode(); | |||
| longFileMode.setValue( mode ); | |||
| } | |||
| /** | |||
| * Set how to handle long files. Allowable values are truncate - paths are | |||
| * truncated to the maximum length fail - paths greater than the maximim | |||
| * cause a build exception warn - paths greater than the maximum cause a | |||
| * warning and GNU is used gnu - GNU extensions are used for any paths | |||
| * greater than the maximum. omit - paths greater than the maximum are | |||
| * omitted from the archive | |||
| * | |||
| * @param mode The new Longfile value | |||
| */ | |||
| public void setLongfile( TarLongFileMode mode ) | |||
| { | |||
| this.longFileMode = mode; | |||
| } | |||
| /** | |||
| * This is the name/location of where to create the tar file. | |||
| * | |||
| * @param tarFile The new Tarfile value | |||
| */ | |||
| public void setTarfile( File tarFile ) | |||
| { | |||
| this.tarFile = tarFile; | |||
| } | |||
| public TarFileSet createTarFileSet() | |||
| { | |||
| TarFileSet fileset = new TarFileSet(); | |||
| filesets.addElement( fileset ); | |||
| return fileset; | |||
| } | |||
| public void execute() | |||
| throws BuildException | |||
| { | |||
| if( tarFile == null ) | |||
| { | |||
| throw new BuildException( "tarfile attribute must be set!", | |||
| location ); | |||
| } | |||
| if( tarFile.exists() && tarFile.isDirectory() ) | |||
| { | |||
| throw new BuildException( "tarfile is a directory!", | |||
| location ); | |||
| } | |||
| if( tarFile.exists() && !tarFile.canWrite() ) | |||
| { | |||
| throw new BuildException( "Can not write to the specified tarfile!", | |||
| location ); | |||
| } | |||
| if( baseDir != null ) | |||
| { | |||
| if( !baseDir.exists() ) | |||
| { | |||
| throw new BuildException( "basedir does not exist!", location ); | |||
| } | |||
| // add the main fileset to the list of filesets to process. | |||
| TarFileSet mainFileSet = new TarFileSet( fileset ); | |||
| mainFileSet.setDir( baseDir ); | |||
| filesets.addElement( mainFileSet ); | |||
| } | |||
| if( filesets.size() == 0 ) | |||
| { | |||
| throw new BuildException( "You must supply either a basdir attribute or some nested filesets.", | |||
| location ); | |||
| } | |||
| // check if tr is out of date with respect to each | |||
| // fileset | |||
| boolean upToDate = true; | |||
| for( Enumeration e = filesets.elements(); e.hasMoreElements(); ) | |||
| { | |||
| TarFileSet fs = ( TarFileSet )e.nextElement(); | |||
| String[] files = fs.getFiles( project ); | |||
| if( !archiveIsUpToDate( files ) ) | |||
| { | |||
| upToDate = false; | |||
| } | |||
| for( int i = 0; i < files.length; ++i ) | |||
| { | |||
| if( tarFile.equals( new File( fs.getDir( project ), files[i] ) ) ) | |||
| { | |||
| throw new BuildException( "A tar file cannot include itself", location ); | |||
| } | |||
| } | |||
| } | |||
| if( upToDate ) | |||
| { | |||
| log( "Nothing to do: " + tarFile.getAbsolutePath() + " is up to date.", | |||
| Project.MSG_INFO ); | |||
| return; | |||
| } | |||
| log( "Building tar: " + tarFile.getAbsolutePath(), Project.MSG_INFO ); | |||
| TarOutputStream tOut = null; | |||
| try | |||
| { | |||
| tOut = new TarOutputStream( new FileOutputStream( tarFile ) ); | |||
| tOut.setDebug( true ); | |||
| if( longFileMode.isTruncateMode() ) | |||
| { | |||
| tOut.setLongFileMode( TarOutputStream.LONGFILE_TRUNCATE ); | |||
| } | |||
| else if( longFileMode.isFailMode() || | |||
| longFileMode.isOmitMode() ) | |||
| { | |||
| tOut.setLongFileMode( TarOutputStream.LONGFILE_ERROR ); | |||
| } | |||
| else | |||
| { | |||
| // warn or GNU | |||
| tOut.setLongFileMode( TarOutputStream.LONGFILE_GNU ); | |||
| } | |||
| longWarningGiven = false; | |||
| for( Enumeration e = filesets.elements(); e.hasMoreElements(); ) | |||
| { | |||
| TarFileSet fs = ( TarFileSet )e.nextElement(); | |||
| String[] files = fs.getFiles( project ); | |||
| for( int i = 0; i < files.length; i++ ) | |||
| { | |||
| File f = new File( fs.getDir( project ), files[i] ); | |||
| String name = files[i].replace( File.separatorChar, '/' ); | |||
| tarFile( f, tOut, name, fs ); | |||
| } | |||
| } | |||
| } | |||
| catch( IOException ioe ) | |||
| { | |||
| String msg = "Problem creating TAR: " + ioe.getMessage(); | |||
| throw new BuildException( msg, ioe, location ); | |||
| } | |||
| finally | |||
| { | |||
| if( tOut != null ) | |||
| { | |||
| try | |||
| { | |||
| // close up | |||
| tOut.close(); | |||
| } | |||
| catch( IOException e ) | |||
| {} | |||
| } | |||
| } | |||
| } | |||
| protected boolean archiveIsUpToDate( String[] files ) | |||
| { | |||
| SourceFileScanner sfs = new SourceFileScanner( this ); | |||
| MergingMapper mm = new MergingMapper(); | |||
| mm.setTo( tarFile.getAbsolutePath() ); | |||
| return sfs.restrict( files, baseDir, null, mm ).length == 0; | |||
| } | |||
| protected void tarFile( File file, TarOutputStream tOut, String vPath, | |||
| TarFileSet tarFileSet ) | |||
| throws IOException | |||
| { | |||
| FileInputStream fIn = null; | |||
| // don't add "" to the archive | |||
| if( vPath.length() <= 0 ) | |||
| { | |||
| return; | |||
| } | |||
| if( file.isDirectory() && !vPath.endsWith( "/" ) ) | |||
| { | |||
| vPath += "/"; | |||
| } | |||
| try | |||
| { | |||
| if( vPath.length() >= TarConstants.NAMELEN ) | |||
| { | |||
| if( longFileMode.isOmitMode() ) | |||
| { | |||
| log( "Omitting: " + vPath, Project.MSG_INFO ); | |||
| return; | |||
| } | |||
| else if( longFileMode.isWarnMode() ) | |||
| { | |||
| log( "Entry: " + vPath + " longer than " + | |||
| TarConstants.NAMELEN + " characters.", Project.MSG_WARN ); | |||
| if( !longWarningGiven ) | |||
| { | |||
| log( "Resulting tar file can only be processed successfully" | |||
| + " by GNU compatible tar commands", Project.MSG_WARN ); | |||
| longWarningGiven = true; | |||
| } | |||
| } | |||
| else if( longFileMode.isFailMode() ) | |||
| { | |||
| throw new BuildException( | |||
| "Entry: " + vPath + " longer than " + | |||
| TarConstants.NAMELEN + "characters.", location ); | |||
| } | |||
| } | |||
| TarEntry te = new TarEntry( vPath ); | |||
| te.setModTime( file.lastModified() ); | |||
| if( !file.isDirectory() ) | |||
| { | |||
| te.setSize( file.length() ); | |||
| te.setMode( tarFileSet.getMode() ); | |||
| } | |||
| te.setUserName( tarFileSet.getUserName() ); | |||
| te.setGroupName( tarFileSet.getGroup() ); | |||
| tOut.putNextEntry( te ); | |||
| if( !file.isDirectory() ) | |||
| { | |||
| fIn = new FileInputStream( file ); | |||
| byte[] buffer = new byte[8 * 1024]; | |||
| int count = 0; | |||
| do | |||
| { | |||
| tOut.write( buffer, 0, count ); | |||
| count = fIn.read( buffer, 0, buffer.length ); | |||
| }while ( count != -1 ); | |||
| } | |||
| tOut.closeEntry(); | |||
| } | |||
| finally | |||
| { | |||
| if( fIn != null ) | |||
| fIn.close(); | |||
| } | |||
| } | |||
| public static class TarFileSet extends FileSet | |||
| { | |||
| private String[] files = null; | |||
| private int mode = 0100644; | |||
| private String userName = ""; | |||
| private String groupName = ""; | |||
| public TarFileSet( FileSet fileset ) | |||
| { | |||
| super( fileset ); | |||
| } | |||
| public TarFileSet() | |||
| { | |||
| super(); | |||
| } | |||
| public void setGroup( String groupName ) | |||
| { | |||
| this.groupName = groupName; | |||
| } | |||
| public void setMode( String octalString ) | |||
| { | |||
| this.mode = 0100000 | Integer.parseInt( octalString, 8 ); | |||
| } | |||
| public void setUserName( String userName ) | |||
| { | |||
| this.userName = userName; | |||
| } | |||
| /** | |||
| * Get a list of files and directories specified in the fileset. | |||
| * | |||
| * @param p Description of Parameter | |||
| * @return a list of file and directory names, relative to the baseDir | |||
| * for the project. | |||
| */ | |||
| public String[] getFiles( Project p ) | |||
| { | |||
| if( files == null ) | |||
| { | |||
| DirectoryScanner ds = getDirectoryScanner( p ); | |||
| String[] directories = ds.getIncludedDirectories(); | |||
| String[] filesPerSe = ds.getIncludedFiles(); | |||
| files = new String[directories.length + filesPerSe.length]; | |||
| System.arraycopy( directories, 0, files, 0, directories.length ); | |||
| System.arraycopy( filesPerSe, 0, files, directories.length, | |||
| filesPerSe.length ); | |||
| } | |||
| return files; | |||
| } | |||
| public String getGroup() | |||
| { | |||
| return groupName; | |||
| } | |||
| public int getMode() | |||
| { | |||
| return mode; | |||
| } | |||
| public String getUserName() | |||
| { | |||
| return userName; | |||
| } | |||
| } | |||
| /** | |||
| * Valid Modes for LongFile attribute to Tar Task | |||
| * | |||
| * @author <a href="mailto:umagesh@apache.org">Magesh Umasankar</a> | |||
| */ | |||
| public static class TarLongFileMode extends EnumeratedAttribute | |||
| { | |||
| // permissable values for longfile attribute | |||
| public final static String WARN = "warn"; | |||
| public final static String FAIL = "fail"; | |||
| public final static String TRUNCATE = "truncate"; | |||
| public final static String GNU = "gnu"; | |||
| public final static String OMIT = "omit"; | |||
| private final String[] validModes = {WARN, FAIL, TRUNCATE, GNU, OMIT}; | |||
| public TarLongFileMode() | |||
| { | |||
| super(); | |||
| setValue( WARN ); | |||
| } | |||
| public String[] getValues() | |||
| { | |||
| return validModes; | |||
| } | |||
| public boolean isFailMode() | |||
| { | |||
| return FAIL.equalsIgnoreCase( getValue() ); | |||
| } | |||
| public boolean isGnuMode() | |||
| { | |||
| return GNU.equalsIgnoreCase( getValue() ); | |||
| } | |||
| public boolean isOmitMode() | |||
| { | |||
| return OMIT.equalsIgnoreCase( getValue() ); | |||
| } | |||
| public boolean isTruncateMode() | |||
| { | |||
| return TRUNCATE.equalsIgnoreCase( getValue() ); | |||
| } | |||
| public boolean isWarnMode() | |||
| { | |||
| return WARN.equalsIgnoreCase( getValue() ); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,84 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.IOException; | |||
| import java.io.OutputStream; | |||
| import org.apache.tools.ant.Task; | |||
| /** | |||
| * 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) | |||
| * @deprecated use LogOutputStream instead. | |||
| */ | |||
| public class TaskOutputStream extends OutputStream | |||
| { | |||
| private StringBuffer line; | |||
| private int msgOutputLevel; | |||
| private Task task; | |||
| /** | |||
| * Constructs a new JavacOutputStream with the given project as the output | |||
| * source for messages. | |||
| * | |||
| * @param task Description of Parameter | |||
| * @param msgOutputLevel Description of Parameter | |||
| */ | |||
| TaskOutputStream( Task task, int msgOutputLevel ) | |||
| { | |||
| this.task = task; | |||
| 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. | |||
| * | |||
| * @param c Description of Parameter | |||
| * @exception IOException Description of Exception | |||
| */ | |||
| 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(); | |||
| task.log( s, msgOutputLevel ); | |||
| line = new StringBuffer(); | |||
| } | |||
| } | |||