在 Apache BSF 或 JSR 223 支援的語言中執行指令碼。
注意:此任務仰賴 Apache Ant 發行版中未包含的外部函式庫。請參閱 函式庫相依性 以取得更多資訊。
此任務可以使用 BSF 指令碼管理員或 JDK 中包含的 JSR 223 管理員。這由 manager 屬性控制。JSR 223 指令碼管理員由 javax
指示。
執行中的專案的所有項目(任務、目標等)都可以從指令碼存取,使用它們的 name 或 id 屬性(只要它們的名稱被視為有效的 Java 識別碼)。這由任務的 setbeans 屬性控制。名稱 project
是專案的預先定義參考,可以用來取代專案名稱。名稱 self
是實際的 <script>
任務執行個體的預先定義參考。
從這些物件,您可以存取 Ant Java API,請參閱 JavaDoc(特別是 Project 和 Script)以取得更多資訊。
如果您在 BSF 中使用 JavaScript,一個很好的資源是 https://www.mozilla.org/rhino/doc.html,因為我們正在使用他們的 JavaScript 解譯器。
指令碼幾乎可以執行任何用 Java 編寫的任務。
Rhino 提供了一個特殊建構函式—JavaAdapter
。有了它,您可以建立一個實作多個介面、延伸類別且您可以覆寫方法的物件。因為這是一個(目前)未記錄的功能,以下是說明的連結:Google Groups:Rhino、enum.js、JavaAdapter?,作者為 Norris Boyd,發表於新聞群組 netscape.public.mozilla.jseng。
如果您以編程方式建立目標,請務必將位置設定為有用的值。特別是,所有目標都應該有不同的位置值。
屬性 | 說明 | 必要 |
---|---|---|
語言 | 指令碼所寫的程式語言。必須是 Apache BSF 或 JSR 223 支援的語言 | 是 |
管理員 |
自 Ant 1.7 起。要使用的指令碼引擎管理員。這可以有三個值之一:auto、 bsf或 javax。
|
否;預設為 auto |
src | 如果不在內嵌,則作為檔案的指令碼位置 | 否 |
encoding | 作為檔案的指令碼編碼。自 Ant 1.10.2 起。 | 否;預設為預設 JVM 字元編碼 |
setbeans | 此屬性控制是否設定執行指令碼中所有屬性、參考和目標的變數。如果此屬性為 false,則只設定 project 和 self 變數。如果此屬性為 true,則設定所有變數。自 Ant 1.7 起 |
否;預設為 true |
classpath | 傳遞到指令碼中的類別路徑。自 Ant 1.7 起 | 否 |
classpathref | 要使用的類別路徑,作為對在其他地方定義的路徑的參考提供。自 Ant 1.7 起 | 否 |
自 Ant 1.7 起
Script
的 classpath 屬性是類別路徑結構,也可以透過巢狀 <classpath>
元素設定。
如果設定類別路徑,則會將其用作目前執行緒內容類別載入器,以及提供給 BSF 管理員的類別載入器。這表示它可用於指定包含 BSF 或 JSR 223 管理員的語言實作的類別路徑。如果想要讓 ${user.home}/.ant/lib 沒有許多特定指令碼語言的 jar 檔案,這會很有用。
注意:(自 Ant 1.7.1 起) 此類別路徑可以用於指定 BSF jar 檔案和/或 BSF jar 檔案中具有引擎的語言的位置。這包括 javascript
、jython
、netrexx
和 jacl
語言。
下列程式片段顯示使用五種不同語言
<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>
請注意,對於 jython
範例,指令碼內容必須從第一個欄位開始。
另請注意,對於 ruby
範例,設定變數的名稱前面會加上 $
。
下列指令碼顯示稍微複雜一點的 JRuby 範例
<script language="ruby"> xmlfiles = Dir.new(".").entries.delete_if { |i| ! (i =~ /\.xml$/) } xmlfiles.sort.each { |i| $self.log(i) } </script>
Groovy 中的相同範例為
<script language="groovy"> xmlfiles = new java.io.File(".").listFiles().findAll{ it =~ "\.xml$"} xmlfiles.sort().each { self.log(it.toString()) } </script>
下列範例顯示使用類別路徑指定 beanshell jar 檔案位置。
<script language="beanshell" setbeans="true"> <classpath> <fileset dir="${user.home}/lang/beanshell" includes="*.jar"/> </classpath> System.out.println("Hello world"); </script>
下列指令碼使用 JavaScript 建立多個 echo
工作並執行它們。
<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>
產生
main: 1 4 9 16 25 36 49 64 81 100 BUILD SUCCESSFUL
現在使用 Java API 和 Ant API 的更複雜範例。目標是要列出 <fileset/>
擷取的所有檔案的大小。
<?xml version="1.0" encoding="UTF-8"?> <project name="MyProject" 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 // importPackage(java.io); importClass(java.io.File); // Nashorn syntax // load("nashorn:mozilla_compat.js"); // or // var File = Java.type('java.io.File'); // Access to Ant-Properties by their names dir = project.getProperty("fs.dir"); includes = MyProject.getProperty("fs.includes"); excludes = self.getProject().getProperty("fs.excludes"); // Create a <fileset dir="" includes=""/> fs = project.createDataType("fileset"); fs.setDir(new File(dir)); fs.setIncludes(includes); 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 = new File(basedir, filename); var size = file.length(); // create and use a Task via Ant API echo = MyProject.createTask("echo"); echo.setMessage(filename + ": " + size + " byte"); echo.perform(); } ]]></script> </target> </project>
我們要使用 Java API。由於我們不想要一直輸入套件簽章,所以我們進行匯入。Rhino 知道兩種不同的匯入陳述式方法:一種是套件,一種是單一類別。預設只有 java
套件可用,所以 java.lang.System
可以直接使用 importClass
/importPackage
匯入。對於其他套件,您必須使用 Packages 為完整分類名稱加上前置詞。例如,Ant 的 FileUtils
類別可以使用 importClass(Packages.org.apache.tools.ant.util.FileUtils)
匯入
在 Java 8 到 Java 14 中,您可以使用內建的 Nashorn JavaScript 引擎,而不是 Rhino(在 Java 7 執行時期可用)。然後,使用 Java.type
作為任何 Java 類別的匯入陳述式,或 相容性指令碼:load("nashorn:mozilla_compat.js");
。
從 Java 15 開始,Nashorn 已再次移除,您需要提供外部 JavaScript 引擎。您最好的選擇可能是 GraalVM JavaScript,它需要您新增許多額外的 jar。對於 GraalVM JavaScript 20.1,您需要 org.graalvm.js:js
、org.graalvm.js:js-engine
,而這些又需要 org.graalvm.regex:regex
、org.graalvm.truffle:truffle-api
、org.graalvm.sdk:graal-sdk
和 com.ibm.icu:icu4j
。GraalVM JavaScript 不是 Nashorn 的替代品,請參閱 Graal 的 Nashorn 移轉指南 以取得更多詳細資料。
在使用 GraalVM JavaScript 時,Ant 會啟用功能 polyglot.js.allowAllAccess
,以允許指令碼使用 Ant 物件。預設它也會啟用 Nashorn 相容性模式,但您可以透過將神奇 Ant 屬性 ant.disable.graal.nashorn.compat
設定為 true
來停用它。
<script>
任務會在 project
名稱下填入 Project 執行個體,所以我們可以使用該參考。另一種方式是使用其指定的名稱,或從任務本身取得其參考。Project 提供用於存取和設定屬性、建立資料類型和任務等等的方法。
在建立 FileSet 物件後,我們透過呼叫其 set 方法來初始化它。然後我們可以使用該物件,就像一般 Ant 工作一樣(例如 <copy>
)。
為了取得檔案大小,我們實例化一個 java.io.File
。因此,我們在此使用一般 Java API。
最後,我們使用 <echo>
工作來產生輸出。該工作並非透過其 execute()
方法執行,因為 perform()
方法(實作於 Task 本身)會在呼叫 execute()
之前和之後進行適當的記錄。
以下是使用 beanshell 建立 Ant 工作的範例。此工作會將檔案集和路徑新增至參考路徑。如果路徑不存在,則會建立。
<!-- 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>
以下是使用此工作從目錄清單建立路徑的範例(使用 Ant-Contrib 的 <for> 工作)
<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>