| <!DOCTYPE html> |
| <!-- |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. |
| The ASF licenses this file to You under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with |
| the License. You may obtain a copy of the License at |
| |
| https://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| --> |
| <html lang="en"> |
| |
| <head> |
| <link rel="stylesheet" type="text/css" href="../stylesheets/style.css"> |
| <title>Script Task</title> |
| </head> |
| |
| <body> |
| |
| <h2 id="script">Script</h2> |
| <h3>Description</h3> |
| <p>Execute a script in a <a href="https://jakarta.apache.org/bsf" target="_top">Apache BSF</a> |
| or <a href="https://jcp.org/aboutJava/communityprocess/maintenance/jsr223/223ChangeLog.html" |
| target="_top">JSR 223</a> supported language. |
| </p> |
| <p><strong>Note</strong>: This task depends on external libraries not included in the Apache Ant |
| distribution. See <a href="../install.html#librarydependencies">Library Dependencies</a> for more |
| information.</p> |
| <p>The task may use the BSF scripting manager or the JSR 223 manager that is included in the JDK. |
| This is controlled by the <var>manager</var> attribute. The JSR 223 scripting manager is |
| indicated by <q>javax</q>.</p> |
| <p>All items (tasks, targets, etc) of the running project are accessible from the script, using |
| either their <var>name</var> or <var>id</var> attributes (as long as their names are considered |
| valid Java identifiers, that is). This is controlled by the <var>setbeans</var> attribute of the |
| task. The name <code class="code">project</code> is a pre-defined reference to the Project, which |
| can be used instead of the project name. The name <code class="code">self</code> is a pre-defined |
| reference to the actual <code><script></code>-Task instance.<br/>From these objects you have |
| access to the Ant Java API, see the <a href="../api/index.html">JavaDoc</a> (especially |
| for <a href="../api/org/apache/tools/ant/Project.html">Project</a> |
| and <a href="../api/org/apache/tools/ant/taskdefs/optional/Script.html">Script</a>) for more |
| information.</p> |
| <p>If you are using JavaScript under BSF, a good resource |
| is <a href="https://www.mozilla.org/rhino/doc.html" |
| target="_top">https://www.mozilla.org/rhino/doc.html</a> as we are using their JavaScript |
| interpreter.</p> |
| <p>Scripts can do almost anything a task written in Java could do.</p> |
| <p>Rhino provides a special construct—the <code>JavaAdapter</code>. With that you can create |
| an object which implements several interfaces, extends classes and for which you can overwrite |
| methods. Because this is an undocumented feature (yet), here is the link to an |
| explanation: <a href="https://groups.google.com/forum/#!msg/netscape.public.mozilla.jseng/YlRQE0OvM8c/F8Mvq-XkpxcJ" |
| target="_top">Google Groups: "Rhino, enum.js, JavaAdapter?"</a> by Norris Boyd in the |
| newsgroup <em>netscape.public.mozilla.jseng</em>.</p> |
| |
| <p>If you are creating Targets programmatically, make sure you set the Location to a useful value. |
| In particular all targets should have different location values.</p> |
| |
| <h3>Parameters</h3> |
| <table class="attr"> |
| <tr> |
| <th scope="col">Attribute</th> |
| <th scope="col">Description</th> |
| <th scope="col">Required</th> |
| </tr> |
| <tr> |
| <td>language</td> |
| <td>The programming language the script is written in. Must be a supported Apache BSF or JSR |
| 223 language</td> |
| <td>Yes</td> |
| </tr> |
| <tr> |
| <td>manager</td> |
| <td> |
| <em>Since Ant 1.7</em>. The script engine manager to use. This can have one of three |
| values: <q>auto</q>, <q>bsf</q> or <q>javax</q>. |
| <ul> |
| <li><q>bsf</q> use the BSF scripting manager to run the language.</li> |
| <li><q>javax</q> use the <code>javax.scripting</code> manager to run the language.</li> |
| <li><q>auto</q> use the BSF engine if it exists, otherwise use |
| the <code>javax.scripting</code> manager.</li> |
| </ul> |
| </td> |
| <td>No; default is <q>auto</q></td> |
| </tr> |
| <tr> |
| <td>src</td> |
| <td>The location of the script as a file, if not inline</td> |
| <td>No</td> |
| </tr> |
| <tr> |
| <td>encoding</td> |
| <td>The encoding of the script as a file. <em>Since Ant 1.10.2</em>.</td> |
| <td>No; defaults to default JVM character encoding</td> |
| </tr> |
| <tr> |
| <td>setbeans</td> |
| <td>This attribute controls whether to set variables for all properties, references and targets |
| in the running script. If this attribute is <q>false</q>, only the the <code>project</code> |
| and <code>self</code> variables are set. If this attribute is <q>true</q> all the variables |
| are set. <em>Since Ant 1.7</em></td> |
| <td>No; defaults to <q>true</q></td> |
| </tr> |
| <tr> |
| <td>classpath</td> |
| <td>The classpath to pass into the script. <em>Since Ant 1.7</em></td> |
| <td>No</td> |
| </tr> |
| <tr> |
| <td>classpathref</td> |
| <td>The classpath to use, given as a <a href="../using.html#references">reference</a> to a path |
| defined elsewhere. |
| <em>Since Ant 1.7</em></td> |
| <td>No</td> |
| </tr> |
| </table> |
| <h3>Parameters specified as nested elements</h3> |
| <h4>classpath</h4> |
| <p><em>Since Ant 1.7</em></p> |
| <p><code>Script</code>'s <var>classpath</var> attribute is a <a href="../using.html#path">path-like |
| structure</a> and can also be set via a nested <code><classpath></code> element. |
| </p> |
| <p>If a classpath is set, it will be used as the current thread context classloader, and as the |
| classloader given to the BSF manager. This means that it can be used to specify the classpath |
| containing the language implementation for BSF or for JSR 223 managers. This can be useful if one |
| wants to keep <samp>${user.home}/.ant/lib</samp> free of lots of scripting language specific jar |
| files.</p> |
| <p><strong>Note</strong>: (<em>since Ant 1.7.1</em>) This classpath <em>can</em> be used to specify |
| the location of the BSF jar file and/or languages that have engines in the BSF jar file. This |
| includes the <q>javascript</q>, <q>jython</q>, <q>netrexx</q> and <q>jacl</q> languages.</p> |
| <h3>Examples</h3> |
| <p>The following snippet shows use of five different languages:</p> |
| <pre> |
| <property name="message" value="Hello world"/> |
| |
| <script language="groovy"> |
| println("message is " + message) |
| </script> |
| |
| <script language="beanshell"> |
| System.out.println("message is " + message); |
| </script> |
| |
| <script language="judoscript"> |
| println 'message is ', message |
| </script> |
| |
| <script language="ruby"> |
| print 'message is ', $message, "\n" |
| </script> |
| |
| <script language="jython"> |
| print "message is %s" % message |
| </script></pre> |
| <p>Note that for the <q>jython</q> example, the script contents <strong>must</strong> start on the |
| first column.</p> |
| <p>Note also that for the <q>ruby</q> example, the names of the set variables are prefixed by |
| a <q>$</q>.</p> |
| <p>The following script shows a little more complicated JRuby example:</p> |
| <pre> |
| <script language="ruby"> |
| xmlfiles = Dir.new(".").entries.delete_if { |i| ! (i =~ /\.xml$/) } |
| xmlfiles.sort.each { |i| $self.log(i) } |
| </script></pre> |
| <p>The same example in Groovy is:</p> |
| <pre> |
| <script language="groovy"> |
| xmlfiles = new java.io.File(".").listFiles().findAll{ it =~ "\.xml$"} |
| xmlfiles.sort().each { self.log(it.toString()) } |
| </script></pre> |
| <p>The following example shows the use of classpath to specify the location of the beanshell jar |
| file.</p> |
| <pre> |
| <script language="beanshell" setbeans="true"> |
| <classpath> |
| <fileset dir="${user.home}/lang/beanshell" includes="*.jar"/> |
| </classpath> |
| System.out.println("Hello world"); |
| </script></pre> |
| <p>The following script uses JavaScript to create a number of <code>echo</code> tasks and execute |
| them.</p> |
| <pre> |
| <project name="squares" default="main" basedir="."> |
| <target name="main"> |
| <script language="javascript"> <![CDATA[ |
| for (i = 1; i <= 10; i++) { |
| echo = squares.createTask("echo"); |
| echo.setMessage(i*i); |
| echo.perform(); |
| } |
| ]]> </script> |
| </target> |
| </project></pre> |
| <p>generates</p> |
| <pre> |
| main: |
| 1 |
| 4 |
| 9 |
| 16 |
| 25 |
| 36 |
| 49 |
| 64 |
| 81 |
| 100 |
| |
| BUILD SUCCESSFUL</pre> |
| |
| <p>Now a more complex example using the Java API and the Ant API. The goal is to list the file sizes |
| of all files a <code><fileset/></code> caught.</p> |
| <pre> |
| <?xml version="1.0" encoding="UTF-8"?> |
| <project name="<span style="color:blue">MyProject</span>" basedir="." default="main"> |
| |
| <property name="fs.dir" value="src"/> |
| <property name="fs.includes" value="**/*.txt"/> |
| <property name="fs.excludes" value="**/*.tmp"/> |
| |
| <target name="main"> |
| <script language="javascript"> <![CDATA[ |
| // import statements |
| <span style="color:blue">// importPackage(java.io)</span>; |
| <span style="color:blue">importClass(java.io.File)</span>; |
| // Nashorn syntax |
| // <span style="color:blue">load("nashorn:mozilla_compat.js");</span> |
| // or |
| // <span style="color:blue">var File = Java.type('java.io.File');</span> |
| |
| |
| // Access to Ant-Properties by their names |
| dir = <span style="color:blue">project</span>.getProperty("fs.dir"); |
| includes = <span style="color:blue">MyProject</span>.getProperty("fs.includes"); |
| excludes = <span style="color:blue">self.getProject()</span>.<span style="color:blue">getProperty("fs.excludes")</span>; |
| |
| // Create a <fileset dir="" includes=""/> |
| fs = project.<span style="color:blue">createDataType("fileset")</span>; |
| fs.setDir(new File(dir)); |
| <span style="color:blue">fs.setIncludes(includes)</span>; |
| fs.setExcludes(excludes); |
| |
| // Get the files (array) of that fileset |
| ds = fs.getDirectoryScanner(project); |
| srcFiles = ds.getIncludedFiles(); |
| |
| // iterate over that array |
| for (i = 0; i < srcFiles.length; i++) { |
| |
| // get the values via Java API |
| var basedir = fs.getDir(project); |
| var filename = srcFiles[i]; |
| var file = <span style="color:blue">new File(basedir, filename)</span>; |
| var size = file.length(); |
| |
| // create and use a Task via Ant API |
| echo = MyProject.<span style="color:blue">createTask("echo")</span>; |
| echo.setMessage(filename + ": " + size + " byte"); |
| echo.<span style="color:blue">perform()</span>; |
| } |
| ]]></script> |
| </target> |
| </project></pre> |
| <p>We want to use the Java API. Because we don't want always typing the package signature we do an |
| import. Rhino knows two different methods for import statements: one for packages and one for a |
| single class. By default only the <code>java</code> packages are available, |
| so <code class="code">java.lang.System</code> can be directly imported |
| with <code>importClass</code>/<code>importPackage</code>. For other packages you have to prefix the |
| full classified name with <strong>Packages</strong>. For example |
| Ant's <code class="code">FileUtils</code> class can be imported |
| with <code class="code">importClass(<strong>Packages</strong>.org.apache.tools.ant.util.FileUtils)</code></p> |
| <p>In Java 8 up until Java 14, you may use the built-in Nashorn JavaScript engine rather than Rhino (which is |
| available in Java 7 runtime). Then, use <code>Java.type</code> as import statement for any Java |
| class |
| or <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/scripting/prog_guide/javascript.html#A1147207">the |
| compatibility script</a>: <code>load("nashorn:mozilla_compat.js");</code>.</p> |
| |
| <p>Starting with Java 15 Nashorn has been removed again and you need |
| to provide an external JavaScript engine. Your best option probably |
| is <a href="https://github.com/graalvm/graaljs">GraalVM |
| JavaScript</a> which requires you to add a lot of extra jars. For |
| GraalVM JavaScript 20.1 you'll |
| need <code>org.graalvm.js:js</code>, <code>org.graalvm.js:js-engine</code> |
| which in turn |
| require <code>org.graalvm.regex:regex</code>, <code>org.graalvm.truffle:truffle-api</code>, <code>org.graalvm.sdk:graal-sdk</code>, |
| and <code>com.ibm.icu:icu4j</code>. GraalVM JavaScript is not a |
| drop-in replacement for Nashorn, see |
| Graal's <a href="https://github.com/graalvm/graaljs/blob/master/docs/user/NashornMigrationGuide.md">Nashorn |
| Migration Guide</a> for more details.</p> |
| |
| <p>When using GraalVM JavaScript Ant will enable the |
| feature <code>polyglot.js.allowAllAccess</code> in order to allow |
| scripts to use Ant objects. By default it will also enable Nashorn |
| compatibility mode, but you can disable this by setting the magic |
| Ant property <code>ant.disable.graal.nashorn.compat</code> |
| to <code>true</code>.</p> |
| |
| <p>The <code><script></code> task populates the Project instance under the |
| name <code class="code">project</code>, so we can use that reference. Another way is to use its |
| given name or getting its reference from the task itself. The Project provides methods for accessing |
| and setting properties, creating DataTypes and Tasks and much more.<br/>After creating a FileSet |
| object we initialize that by calling its set-methods. Then we can use that object like a normal Ant |
| task (<code><copy></code> for example).<br/>For getting the size of a file we instantiate |
| a <code class="code">java.io.File</code>. So we are using normal Java API here.<br/>Finally we use |
| the <code><echo></code> task for producing the output. The task is not executed by |
| its <code class="code">execute()</code> method, because the <code class="code">perform()</code> |
| method (implemented in Task itself) does the appropriate logging before and after |
| invoking <code class="code">execute()</code>.</p> |
| <p>Here is an example of using beanshell to create an Ant task. This task will add filesets and |
| paths to a referenced path. If the path does not exist, it will be created.</p> |
| <pre> |
| <!-- |
| Define addtopath task |
| --> |
| <script language="beanshell"> |
| import org.apache.tools.ant.Task; |
| import org.apache.tools.ant.types.Path; |
| import org.apache.tools.ant.types.FileSet; |
| public class AddToPath extends Task { |
| private Path path; |
| public void setRefId(String id) { |
| path = getProject().getReference(id); |
| if (path == null) { |
| path = new Path(getProject()); |
| getProject().addReference(id, path); |
| } |
| } |
| public void add(Path c) { |
| path.add(c); |
| } |
| public void add(FileSet c) { |
| path.add(c); |
| } |
| public void execute() { |
| // Do nothing |
| } |
| } |
| project.addTaskDefinition("addtopath", AddToPath.class); |
| </script></pre> |
| <p>An example of using this task to create a path from a list of directories (using |
| Ant-Contrib's <a href="http://ant-contrib.sourceforge.net/tasks/tasks/for.html" |
| target="_top"><for></a> task) follows:</p> |
| <pre> |
| <path id="main.path"> |
| <fileset dir="build/classes"/> |
| </path> |
| <ac:for param="ref" list="commons,fw,lps" |
| xmlns:ac="antlib:net.sf.antcontrib"> |
| <sequential> |
| <addtopath refid="main.path"> |
| <fileset dir="${dist.dir}/@{ref}/main" |
| includes="**/*.jar"/> |
| </addtopath> |
| </sequential> |
| </ac:for></pre> |
| |
| </body> |
| </html> |