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(); | |||||
| } | |||||
| } | |||||