You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ant.apache.org by bu...@apache.org on 2003/01/21 00:49:01 UTC
DO NOT REPLY [Bug 16279] New: -
Velocity task
DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG
RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT
<http://nagoya.apache.org/bugzilla/show_bug.cgi?id=16279>.
ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND
INSERTED IN THE BUG DATABASE.
http://nagoya.apache.org/bugzilla/show_bug.cgi?id=16279
Velocity task
Summary: Velocity task
Product: Ant
Version: 1.5.1
Platform: All
OS/Version: All
Status: NEW
Severity: Enhancement
Priority: Other
Component: Optional Tasks
AssignedTo: ant-dev@jakarta.apache.org
ReportedBy: hnakamur@v003.vaio.ne.jp
The <velocity> task is meant to be a richer version of filter function
of the <copy> task. I have been using the filter function for replacing
parameters in configuration files. But I need more functionality than
just replacing. I think this is where Velocity comes in. This template
engine has directives like #if and #foreach, so it is more powerful.
The <velocity> task has attributes and nested elements similar to the
<copy> task. I thought it would be easy to use. But not all of <copy>
attributes are supported. Please see the velocity.html in the patch.
Here is a example of calling a <velocity> task:
<velocity todir="c" propertyfile="velocity.properties">
<velocitycontext>
<contextdata key="a" value="A1"/>
<contextdata key="b" value="B1" if="SOME_PROP"/>
<contextdata key="b" value="B2" unless="SOME_PROP"/>
<contextdata key="str" classname="my.package.StringTool"/>
</velocitycontext>
<fileset dir="a">
<include name="**/*.vm"/>
</fileset>
<mapper type="glob" from="*.vm" to="*.html"/>
</velocity>
Opinions and suggestions are welcome.
Here is the patch for the <velocity> task:
diff -ruN jakarta-ant-1.5.1.orig/docs/manual/OptionalTasks/velocity.html
jakarta-ant-1.5.1/docs/manual/OptionalTasks/velocity.html
--- jakarta-ant-1.5.1.orig/docs/manual/OptionalTasks/velocity.html 1970-01-01
09:00:00.000000000 +0900
+++ jakarta-ant-1.5.1/docs/manual/OptionalTasks/velocity.html 2003-01-21
07:39:03.000000000 +0900
@@ -0,0 +1,232 @@
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<title>Velocity Task</title>
+</head>
+
+<body>
+
+<h2><a name="velocity">Velocity</a></h2>
+<h3>Description</h3>
+<p>Run <a href="http://jakarta.apache.org/velocity/index.html"
target="_top">Jakarta-Velocity</a> on a file or FileSet to a new
file or directory.
+By default, files are only copied if the source file is newer than the
+destination file, or when the destination file does not exist. However,
+you can explicitly overwrite files with the <code>overwrite</code>
attribute.</p>
+<p><a href="../CoreTypes/fileset.html">FileSet</a>s are used to select a
+set of files to copy.
+To use a <code><fileset></code>, the <code>todir</code> attribute
+must be set.</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+ <tr>
+ <td valign="top"><b>Attribute</b></td>
+ <td valign="top"><b>Description</b></td>
+ <td align="center" valign="top"><b>Required</b></td>
+ </tr>
+ <tr>
+ <td valign="top">propertyfile</td>
+ <td valign="top">The property file which is used to initialize Velocity.
+ </td>
+ <td valign="top" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td valign="top">file</td>
+ <td valign="top">The file to copy.</td>
+ <td valign="top" align="center">Yes, unless a nested
+ <code><fileset></code> element is used.</td>
+ </tr>
+ <tr>
+ <td valign="top">tofile</td>
+ <td valign="top">The file to copy to.</td>
+ <td valign="top" align="center" rowspan="2">With the <code>file</code>
+ attribute, either <code>tofile</code> or <code>todir</code> can be used.
+ With nested <code><fileset></code> elements, if the set of files
+ is greater than 1, or if only the <code>dir</code> attribute is
+ specified in the <code><fileset></code>, or if the
+ <code>file</code> attribute is also specified, then only
+ <code>todir</code> is allowed.</td>
+ </tr>
+ <tr>
+ <td valign="top">todir</td>
+ <td valign="top">The directory to copy to.</td>
+ </tr>
+ <tr>
+ <td valign="top">overwrite</td>
+ <td valign="top">Overwrite existing files even if the destination
+ files are newer.</td>
+ <td valign="top" align="center">No; defaults to false.</td>
+ </tr>
+ <tr>
+ <td valign="top">flatten</td>
+ <td valign="top">Ignore the directory structure of the source files,
+ and copy all files into the directory specified by the <code>todir</code>
+ attribute. Note that you can achieve the same effect by using a
+ <a href="../CoreTypes/mapper.html#flatten-mapper">flatten
mapper</a>.</td>
+ <td valign="top" align="center">No; defaults to false.</td>
+ </tr>
+ <tr>
+ <td valign="top">failonerror</td>
+ <td valign="top">Log a warning message, but do not stop the build,
+ when the file to copy does not exist.
+ Only meaningful when copying a single file.
+ </td>
+ <td valign="top" align="center">No; defaults to true.</td>
+ </tr>
+ <tr>
+ <td valign="top">templatebasedir</td>
+ <td valign="top">The template base directory. This is used to
+ caclutate a relative path of a template file. Velocity receives a
+ relative path and searches a template file in Velocity's search paths.
+ </td>
+ <td valign="top" align="center">No; defaults to project basedir.</td>
+ </tr>
+</table>
+<h3>Parameters specified as nested elements</h3>
+
+<h4>velocitycontext</h4>
+ <p>A <velocitycontext> is used to specify the VelocityContext data.
+ It has nested <contextdata> elements.</p>
+
+<h4>contextdata</h4>
+ <p>A <contextdata> is a nested element of <velocitycontext>
+ and is used to specify a VelocityContext datum.</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+ <tr>
+ <td valign="top"><b>Attribute</b></td>
+ <td valign="top"><b>Description</b></td>
+ <td align="center" valign="top"><b>Required</b></td>
+ </tr>
+ <tr>
+ <td valign="top">key</td>
+ <td valign="top">The key of a VelocityContext datum.
+ </td>
+ <td valign="top" align="center">Yes</td>
+ </tr>
+ <tr>
+ <td valign="top">value</td>
+ <td valign="top">The value of a VelocityContext datum.</td>
+ <td valign="top" align="center" rowspan="2">One of either <var>value</var>
+ or <var>classname</var>.</td>
+ </tr>
+ <tr>
+ <td valign="top">classname</td>
+ <td valign="top">An instance of this classname is used as a VelocityContext
+ datum. The specified class must have the public non-argument constructor.
+ And if the class has a public method
+ <code>setContext(org.apache.velocity.context.Context)</code>,
+ it is invoked by reflection.
+ </td>
+ </tr>
+ <tr>
+ <td valign="top">if</td>
+ <td valign="top">Only use this data if the named property is set.</td>
+ <td align="center" valign="top">No</td>
+ </tr>
+ <tr>
+ <td valign="top">unless</td>
+ <td valign="top">Only use this data if the named property is
+ <b>not</b> set.</td>
+ <td align="center" valign="top">No</td>
+ </tr>
+</table>
+
+<h4>fileset</h4>
+ <p><a href="../CoreTypes/fileset.html">FileSet</a>s are used to select
+sets of files to run velocity on.
+ To use a fileset, the <code>todir</code> attribute must be set.</p>
+
+<h4>mapper</h4>
+ <p>You can define filename transformations by using a nested <a
+ href="../CoreTypes/mapper.html">mapper</a> element. The default mapper used by
+ <code><velocity></code> is the <a
+ href="../CoreTypes/mapper.html#identity-mapper">identity mapper</a>.</p>
+
+<h3>Examples</h3>
+<p><b>Run velocity on a single file</b></p>
+<pre>
+ <velocity file="myfile.txt" tofile="mycopy.txt"
+ propertyfile="velocity.properties">
+ <velocitycontext>
+ <contextdata key="key1" value="value1"/>
+ <contextdata key="key2"
classname="some.Class1"/>
+ <contextdata key="key3" value="value3"
if="SOME_PROPERTY"/>
+ <contextdata key="key4" value="value4"
unless="SOME_PROPERTY"/>
+ </velocitycontext>
+ </velocity>
+</pre>
+<p><b>Run velocity on a single file to a directory</b></p>
+<pre>
+ <velocity file="myfile.txt" todir="../some/other/dir"
+ propertyfile="velocity.properties">
+ <velocitycontext>
+ <contextdata key="key1" value="value1"/>
+ <contextdata key="key2"
classname="some.Class1"/>
+ <contextdata key="key3" value="value3"
if="SOME_PROPERTY"/>
+ <contextdata key="key4" value="value4"
unless="SOME_PROPERTY"/>
+ </velocitycontext>
+ </velocity>
+</pre>
+<p><b>Run velocity on a set of files to a directory</b></p>
+<pre>
+ <velocity todir="../dest/dir"
+ propertyfile="velocity.properties">
+ <velocitycontext>
+ <contextdata key="key1" value="value1"/>
+ <contextdata key="key2"
classname="some.Class1"/>
+ <contextdata key="key3" value="value3"
if="SOME_PROPERTY"/>
+ <contextdata key="key4" value="value4"
unless="SOME_PROPERTY"/>
+ </velocitycontext>
+ <fileset dir="src_dir">
+ <exclude name="**/*.java"/>
+ </fileset>
+ </velocity>
+
+ <velocity todir="../dest/dir"
+ propertyfile="velocity.properties">
+ <velocitycontext>
+ <contextdata key="key1" value="value1"/>
+ <contextdata key="key2"
classname="some.Class1"/>
+ <contextdata key="key3" value="value3"
if="SOME_PROPERTY"/>
+ <contextdata key="key4" value="value4"
unless="SOME_PROPERTY"/>
+ </velocitycontext>
+ <fileset dir="src_dir" excludes="**/*.java"/>
+ </velocity>
+</pre>
+<p><b>Run velocity on a set of files to a directory, appending
+<code>.bak</code> to the file name on the fly</b></p>
+<pre>
+ <velocity todir="../backup/dir"
+ propertyfile="velocity.properties">
+ <velocitycontext>
+ <contextdata key="key1" value="value1"/>
+ <contextdata key="key2"
classname="some.Class1"/>
+ <contextdata key="key3" value="value3"
if="SOME_PROPERTY"/>
+ <contextdata key="key4" value="value4"
unless="SOME_PROPERTY"/>
+ </velocitycontext>
+ <fileset dir="src_dir"/>
+ <mapper type="glob" from="*"
to="*.bak"/>
+ </velocity>
+</pre>
+
+<p><strong>Unix Note:</strong> Destination file permissions are not the same as
+the template files; they end up with the default <code>UMASK</code> permissions
+instead. This
+is caused by the lack of any means to query or set file permissions in the
+current Java runtimes.
+</p>
+
+<p><strong>Windows Note:</strong> If you a destination file already exists,
+but with different casing, the destination file takes on the case of the
+original. The workaround is to
+<a href="delete.html">delete</a>
+the file in the destination directory before you run velocity.
+</p>
+
+<hr><p align="center">Copyright © 2003 Apache Software Foundation.
+All rights Reserved.</p>
+
+</body>
+</html>
+
diff -ruN jakarta-ant-1.5.1.orig/docs/manual/install.html jakarta-ant-
1.5.1/docs/manual/install.html
--- jakarta-ant-1.5.1.orig/docs/manual/install.html 2002-10-02
11:10:18.000000000 +0900
+++ jakarta-ant-1.5.1/docs/manual/install.html 2003-01-21 07:37:06.000000000
+0900
@@ -381,6 +381,12 @@
<td><a href="http://www.clarkware.com/software/JDepend.html"
target="_top">http://www.clarkware.com/software/JDepend.html</a></td>
</tr>
+ <tr>
+ <td>Velocity JAR(s)</td>
+ <td>velocity task</td>
+ <td><a href="http://jakarta.apache.org/velocity/index.html"
+ target="_top">http://jakarta.apache.org/velocity/index.html</a></td>
+ </tr>
</table>
<br>
<hr>
diff -ruN jakarta-ant-1.5.1.orig/docs/manual/optionaltasklist.html jakarta-ant-
1.5.1/docs/manual/optionaltasklist.html
--- jakarta-ant-1.5.1.orig/docs/manual/optionaltasklist.html 2002-10-02
11:10:06.000000000 +0900
+++ jakarta-ant-1.5.1/docs/manual/optionaltasklist.html 2003-01-20
09:40:43.000000000 +0900
@@ -62,6 +62,7 @@
<a href="OptionalTasks/test.html">Test</a><br>
<a href="OptionalTasks/translate.html">Translate</a><br>
<a href="Integration/VAJAntTool.html#tasks">Visual Age for Java Tasks</a><br>
+<a href="OptionalTasks/velocity.html">Velocity</a><br>
<a href="OptionalTasks/vss.html#tasks">Microsoft Visual SourceSafe
Tasks</a><br>
<a href="OptionalTasks/wljspc.html">Weblogic JSP Compiler</a><br>
<a href="OptionalTasks/xmlvalidate.html">XmlValidate</a><br>
diff -ruN jakarta-ant-
1.5.1.orig/src/main/org/apache/tools/ant/taskdefs/defaults.properties
jakarta-ant-1.5.1/src/main/org/apache/tools/ant/taskdefs/defaults.properties
--- jakarta-ant-
1.5.1.orig/src/main/org/apache/tools/ant/taskdefs/defaults.properties 2002-10-
02 11:08:34.000000000 +0900
+++ jakarta-ant-
1.5.1/src/main/org/apache/tools/ant/taskdefs/defaults.properties 2003-01-21
07:29:56.000000000 +0900
@@ -169,6 +169,7 @@
jarlib-
available=org.apache.tools.ant.taskdefs.optional.extension.JarLibAvailableTask
jarlib-
resolve=org.apache.tools.ant.taskdefs.optional.extension.JarLibResolveTask
setproxy=org.apache.tools.ant.taskdefs.optional.net.SetProxy
+velocity=org.apache.tools.ant.taskdefs.optional.VelocityTask
# deprecated ant tasks (kept for back compatibility)
starteam=org.apache.tools.ant.taskdefs.optional.scm.AntStarTeamCheckOut
diff -ruN jakarta-ant-
1.5.1.orig/src/main/org/apache/tools/ant/taskdefs/optional/VelocityTask.java
jakarta-ant-
1.5.1/src/main/org/apache/tools/ant/taskdefs/optional/VelocityTask.java
--- jakarta-ant-
1.5.1.orig/src/main/org/apache/tools/ant/taskdefs/optional/VelocityTask.java
1970-01-01 09:00:00.000000000 +0900
+++ jakarta-ant-
1.5.1/src/main/org/apache/tools/ant/taskdefs/optional/VelocityTask.java 2003-01-
20 10:48:52.000000000 +0900
@@ -0,0 +1,478 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-2002 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStreamWriter;
+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.Task;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Mapper;
+import org.apache.tools.ant.types.optional.velocity.VelocityContext;
+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.velocity.app.Velocity;
+import org.apache.velocity.context.Context;
+
+
+/**
+ * Run velocity on a file or a fileset to a new file
+ * or directory. Velocity is only run for a file which 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 task is supposed to be a richer version of filter function
+ * of copy task, and has similar attributes and nested elements.</p>
+ *
+ * @author <a href="mailto:hnakamur@v003.vaio.ne.jp">Hiroaki Nakamura</a>
+ *
+ * @version $Revision$
+ */
+public class VelocityTask extends Task {
+ protected File templateBaseDir = null;
+ protected File file = null; // the template file
+ protected File destFile = null; // the destination file
+ protected File destDir = null; // the destination directory
+ protected String encoding = System.getProperty("file.encoding"); //
template and output file encoding
+ protected File propertyFile = null; // the destination file
+ protected VelocityContext velocityContext; // the <velocitycontext> nested
element
+ protected Vector filesets = new Vector();
+
+ protected boolean forceOverwrite = false;
+ private boolean failonerror = true;
+
+ protected boolean flatten = false;
+ protected Mapper mapperElement = null;
+
+ private FileUtils fileUtils;
+
+ /**
+ * Velocity task constructor.
+ */
+ public VelocityTask() {
+ fileUtils = FileUtils.newFileUtils();
+ }
+
+ protected FileUtils getFileUtils() {
+ return fileUtils;
+ }
+
+ /**
+ * Sets template files base directory.
+ */
+ public void setTemplateBaseDir(File dir) {
+ this.templateBaseDir = dir;
+ }
+
+ /**
+ * @return templatebasedir attribute value or project basedir if
templatebasedir is not set.
+ */
+ protected File getTemplateBaseDir() {
+ return templateBaseDir == null
+ ? project.getBaseDir() : templateBaseDir;
+ }
+
+ /**
+ * Sets a single source file to copy.
+ */
+ public void setFile(File file) {
+ this.file = file;
+ }
+
+ /**
+ * Sets the destination file.
+ */
+ public void setTofile(File destFile) {
+ this.destFile = destFile;
+ }
+
+ /**
+ * Sets the destination directory.
+ */
+ public void setTodir(File destDir) {
+ this.destDir = destDir;
+ }
+
+ /**
+ * Sets the Velocity propertyfile.
+ */
+ public void setPropertyFile(File propertyFile) {
+ this.propertyFile = propertyFile;
+ }
+
+ /**
+ * Sets the encoding.
+ */
+ public void setEncoding(String encoding) {
+ this.encoding = encoding;
+ }
+
+ /**
+ * Create a nested velocitycontext element.
+ */
+ public VelocityContext createVelocityContext() throws BuildException {
+ if (velocityContext != null) {
+ throw new BuildException("Cannot define more than one
velocitycontext",
+ location);
+ }
+ velocityContext = new VelocityContext();
+ return velocityContext;
+ }
+
+ /**
+ * Adds a set of files to copy.
+ */
+ public void addFileset(FileSet set) {
+ filesets.addElement(set);
+ }
+
+ /**
+ * Overwrite any existing destination file(s).
+ */
+ public void setOverwrite(boolean overwrite) {
+ this.forceOverwrite = overwrite;
+ }
+
+ /**
+ * If false, note errors to the output but keep going.
+ * @param failonerror true or false
+ */
+ public void setFailOnError(boolean failonerror) {
+ this.failonerror = failonerror;
+ }
+
+ /**
+ * 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.
+ */
+ public void setFlatten(boolean flatten) {
+ this.flatten = flatten;
+ }
+
+ /**
+ * Defines the mapper to map source to destination files.
+ */
+ 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 velocity template merge operation.
+ */
+ public void execute() throws BuildException {
+ File savedFile = file; // may be altered in validateAttributes
+ File savedDestFile = destFile;
+ File savedDestDir = destDir;
+ FileSet savedFileSet = null;
+ if (file == null && destFile != null && filesets.size() == 1) {
+ // will be removed in validateAttributes
+ savedFileSet = (FileSet) filesets.elementAt(0);
+ }
+
+ validateAttributes();
+
+ try {
+ initVelocity();
+ Context ctx = createContext();
+ File tmplBaseDir = getTemplateBaseDir();
+
+ if (file != null) {
+ if (!file.exists()) {
+ String message = "Warning: Could not find template file "
+ + file.getAbsolutePath() + ".";
+ if (!failonerror) {
+ log(message);
+ } else {
+ throw new BuildException(message);
+ }
+ }
+
+ if (destFile == null) {
+ destFile = new File(destDir, file.getName());
+ }
+
+ mergeTemplateUnlessUpToDate(
+ tmplBaseDir,
+ file,
+ ctx,
+ destFile);
+ }
+
+ if (filesets != null) {
+ FileNameMapper mapper = getFileNameMapper();
+ for (Enumeration en = filesets.elements(); en.hasMoreElements
();) {
+ FileSet fs = (FileSet) en.nextElement();
+ DirectoryScanner ds = fs.getDirectoryScanner(project);
+ File dsBaseDir = ds.getBasedir();
+ String[] files = ds.getIncludedFiles();
+ for (int i = 0; i < files.length; i++) {
+ String srcRelativePath = files[i];
+ File srcFile = new File(dsBaseDir, srcRelativePath);
+ String[] destRelativePaths = mapper.mapFileName
(srcRelativePath);
+ for (int j = 0; j < destRelativePaths.length; j++) {
+ String destRelativePath = destRelativePaths[j];
+ File curDestFile = new File(destDir,
destRelativePath);
+ mergeTemplateUnlessUpToDate(
+ tmplBaseDir,
+ srcFile,
+ ctx,
+ curDestFile);
+ }
+ }
+ }
+ }
+ } finally {
+ // clean up again, so this instance can be used a second
+ // time
+ file = savedFile;
+ destFile = savedDestFile;
+ destDir = savedDestDir;
+ if (savedFileSet != null && filesets.size() == 0) {
+ filesets.insertElementAt(savedFileSet, 0);
+ }
+ }
+ }
+
+//************************************************************************
+// 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.
+ */
+ 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) {
+ throw new BuildException(
+ "Cannot perform operation from directory to file.");
+ } else if (srcFiles.length == 1) {
+ if (file == null) {
+ file = new File(ds.getBasedir(), srcFiles[0]);
+ filesets.removeElementAt(0);
+ } else {
+ throw new BuildException("Cannot concatenate multiple "
+ + "files into a single
file.");
+ }
+ } else {
+ throw new BuildException("Cannot concatenate multiple "
+ + "files into a single file.");
+ }
+ }
+ }
+
+ if (destFile != null) {
+ destDir = fileUtils.getParentFile(destFile);
+ }
+
+ }
+
+ /**
+ * @return FileNameMapper instance
+ */
+ protected FileNameMapper getFileNameMapper() {
+ FileNameMapper mapper = null;
+ if (mapperElement != null) {
+ mapper = mapperElement.getImplementation();
+ } else if (flatten) {
+ mapper = new FlatFileNameMapper();
+ } else {
+ mapper = new IdentityMapper();
+ }
+ return mapper;
+ }
+
+ /**
+ * Initializes Velocity.
+ */
+ protected void initVelocity() throws BuildException {
+ if (propertyFile == null) {
+ throw new BuildException("propertyfile must be set");
+ }
+ try {
+ Velocity.init(propertyFile.getPath());
+ } catch (Exception ex) {
+ throw new BuildException(ex);
+ }
+ }
+
+ /**
+ * Merge Velocity template file to the corresponding destination file
+ * if the destination file is older than the template file or does not
exist.
+ */
+ protected void mergeTemplateUnlessUpToDate(
+ File templateBaseDir,
+ File templateFile,
+ Context ctx,
+ File destFile)
+ throws BuildException {
+
+ if (forceOverwrite ||
+ (templateFile.lastModified() > destFile.lastModified())) {
+ String templatePath = getRelativePath(templateFile,
templateBaseDir);
+ mergeTemplate(templatePath, ctx, destFile);
+ } else {
+ log(templateFile + " omitted as " + destFile
+ + " is up to date.", Project.MSG_VERBOSE);
+ }
+ }
+
+ /**
+ * Merge Velocity template file to the corresponding destination file.
+ */
+ protected void mergeTemplate(
+ String templateRelativePath,
+ Context ctx,
+ File destFile)
+ throws BuildException {
+ try {
+ File destDir = fileUtils.getParentFile(destFile);
+ if (!destDir.exists()) {
+ destDir.mkdirs();
+ }
+
+ OutputStreamWriter osw = null;
+ FileOutputStream fos = new FileOutputStream(destFile);
+ try {
+ osw = new OutputStreamWriter(fos, encoding);
+ try {
+ Velocity.mergeTemplate(
+ templateRelativePath,
+ encoding,
+ ctx,
+ osw);
+ } finally {
+ osw.close();
+ fos = null;
+ }
+ } finally {
+ if (fos != null) {
+ fos.close();
+ }
+ }
+ } catch (Exception ex) {
+ throw new BuildException(ex);
+ }
+ }
+
+ /**
+ * @return relative path of file from baseDir
+ */
+ protected String getRelativePath(File file, File baseDir) {
+ int trimLen = baseDir.getAbsolutePath().length();
+ if (!isRootDirectory(baseDir)) {
+ trimLen++;
+ }
+ return file.getAbsolutePath().substring(trimLen);
+ }
+
+ /**
+ * @return whether dir is root directory or not.
+ */
+ protected boolean isRootDirectory(File dir) {
+ return dir.getParent() == null;
+ }
+
+ /**
+ * @return Velocity context created.
+ */
+ protected Context createContext()
+ throws BuildException {
+ return velocityContext.createRealContext();
+ }
+}
diff -ruN jakarta-ant-
1.5.1.orig/src/main/org/apache/tools/ant/types/optional/velocity/VelocityContext
.java
jakarta-ant-
1.5.1/src/main/org/apache/tools/ant/types/optional/velocity/VelocityContext.java
--- jakarta-ant-
1.5.1.orig/src/main/org/apache/tools/ant/types/optional/velocity/VelocityContext
.java 1970-01-01 09:00:00.000000000
+0900
+++ jakarta-ant-
1.5.1/src/main/org/apache/tools/ant/types/optional/velocity/VelocityContext.java
2003-01-20 11:00:10.000000000 +0900
@@ -0,0 +1,258 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-2002 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.tools.ant.types.optional.velocity;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+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.types.DataType;
+import org.apache.velocity.context.Context;
+
+/**
+ * A VelocityContext is a nested element of Velocity task.
+ * It has nested <code><contextdata></code> elements.
+ *
+ * @author <a href="mailto:hnakamur@v003.vaio.ne.jp">Hiroaki Nakamura</a>
+ *
+ * @version $Revision$
+ */
+public class VelocityContext extends DataType {
+ private Vector contextData = new Vector();
+
+ /**
+ * Creates the nested <code><contextdata></code> element.
+ */
+ public ContextData createContextData() throws BuildException {
+ ContextData cd = new ContextData();
+ contextData.addElement(cd);
+ return cd;
+ }
+
+ /**
+ * @return real org.apache.velocity.VelocityContext specified by
+ * <code><velocitycontext></code> element.
+ */
+ public Context createRealContext()
+ throws BuildException {
+ Context context = new org.apache.velocity.VelocityContext();
+ populateContext(context);
+ return context;
+ }
+
+ /**
+ * Populates org.apache.velocity.VelocityContext with data specified by
+ * nested <code><contextdata></code> elements.
+ */
+ protected void populateContext(Context context)
+ throws BuildException {
+ for (Enumeration en = contextData.elements(); en.hasMoreElements();) {
+ Object o = en.nextElement();
+ ContextData cd = (ContextData) o;
+ cd.addIfValid(context);
+ }
+ }
+
+ /**
+ * ContextData represents a nested <code><contextdata></code> element.
+ * The attribute <code>key</code> is necessary. One of attribute
<code>value</code>
+ * or <code>className</code> is necessary. The attribute <code>value</code>
+ * is used to create immediate Context data. The attribute
<code>className</code>
+ * is used to create a "tool" object which is later used from template
files.
+ * The attribute <code>if</code> and <code>unless</code> are optional,
which
+ * are used to control of enabling or disabling of a
<code><contextdata></code>
+ * element.
+ */
+ public class ContextData {
+ protected String key;
+ protected String value;
+ protected String ifCond;
+ protected String className;
+ protected String unlessCond;
+
+ /**
+ * Sets the key.
+ * @param name The key to set
+ */
+ public void setKey(String key) {
+ this.key = key;
+ }
+
+ /**
+ * Sets the value.
+ * @param value The value to set
+ */
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ /**
+ * Sets the className.
+ * @param className The className to set
+ */
+ public void setClassName(String className) {
+ this.className = className;
+ }
+
+ /**
+ * Sets the ifCond.
+ * @param ifCond The ifCond to set
+ */
+ public void setIf(String ifCond) {
+ this.ifCond = ifCond;
+ }
+
+ /**
+ * Sets the unlessCond.
+ * @param unlessCond The unlessCond to set
+ */
+ public void setUnless(String unlessCond) {
+ this.unlessCond = unlessCond;
+ }
+
+ /**
+ * @return whether this element is valid or not
+ */
+ public boolean isValid() {
+ Project p = getProject();
+ if (ifCond != null && p.getProperty(ifCond) == null) {
+ return false;
+ } else if (unlessCond != null && p.getProperty(unlessCond) !=
null) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Add to a context if this element is valid.
+ */
+ public void addIfValid(Context context)
+ throws BuildException {
+ if (!isValid()) {
+ return;
+ }
+
+ if (key == null) {
+ throw new BuildException("name must be set");
+ }
+
+ if (value != null && className != null) {
+ throw new BuildException("value and className cannot both be
set");
+ } else if (value == null && className == null) {
+ throw new BuildException("value or className must be set");
+ }
+
+ if (value != null) {
+ context.put(key, value);
+ } else if (className != null) {
+ Object instance = createInstance(className);
+ invokeSetContext(instance, context);
+ context.put(key, instance);
+ }
+ }
+
+ /**
+ * @return an instance of the specified class.
+ */
+ protected Object createInstance(String className)
+ throws BuildException {
+ try {
+ return Class.forName(className).newInstance();
+ } catch (ClassNotFoundException ex) {
+ throw new BuildException(ex);
+ } catch (IllegalAccessException ex) {
+ throw new BuildException(ex);
+ } catch (InstantiationException ex) {
+ throw new BuildException(ex);
+ }
+ }
+
+ protected void invokeSetContext(Object instance, Context context)
+ throws BuildException {
+ try {
+ Class[] paramTypes = { Context.class };
+ Method method = instance.getClass().getMethod("setContext",
paramTypes);
+ Object[] args = { context };
+ method.invoke(instance, args);
+ } catch (NoSuchMethodException ex) {
+ // ignore
+ } catch (IllegalAccessException ex) {
+ throw new BuildException(ex);
+ } catch (InvocationTargetException ex) {
+ throw new BuildException(ex);
+ }
+ }
+
+ /**
+ * @return a string representation of an instance.
+ */
+ public String toString() {
+ return "ContextVar[name="
+ + key
+ + ", value="
+ + value
+ + ", className="
+ + className
+ + ", if="
+ + ifCond
+ + ", unless="
+ + unlessCond
+ + "]";
+ }
+ }
+}
--
To unsubscribe, e-mail: <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>