| @@ -42,6 +42,7 @@ | |||||
| <property name="ant.package" value="org/apache/tools/ant"/> | <property name="ant.package" value="org/apache/tools/ant"/> | ||||
| <property name="taskdefs.package" value="${ant.package}/taskdefs"/> | <property name="taskdefs.package" value="${ant.package}/taskdefs"/> | ||||
| <property name="condition.package" value="${taskdefs.package}/condition"/> | <property name="condition.package" value="${taskdefs.package}/condition"/> | ||||
| <property name="modules.package" value="${taskdefs.package}/modules"/> | |||||
| <property name="optional.package" value="${taskdefs.package}/optional"/> | <property name="optional.package" value="${taskdefs.package}/optional"/> | ||||
| <property name="type.package" value="${ant.package}/types"/> | <property name="type.package" value="${ant.package}/types"/> | ||||
| <property name="optional.type.package" value="${type.package}/optional"/> | <property name="optional.type.package" value="${type.package}/optional"/> | ||||
| @@ -178,6 +179,10 @@ | |||||
| =================================================================== | =================================================================== | ||||
| --> | --> | ||||
| <selector id="needs.jdk9+"> | |||||
| <filename name="${modules.package}/"/> | |||||
| </selector> | |||||
| <!-- Kaffe has some JDK 1.5 features including java.lang.Readable, | <!-- Kaffe has some JDK 1.5 features including java.lang.Readable, | ||||
| but not all of them --> | but not all of them --> | ||||
| <selector id="not.in.kaffe"> | <selector id="not.in.kaffe"> | ||||
| @@ -609,6 +614,7 @@ | |||||
| <selector id="conditional-patterns"> | <selector id="conditional-patterns"> | ||||
| <not> | <not> | ||||
| <or> | <or> | ||||
| <selector refid="needs.jdk9+" unless="jdk9+"/> | |||||
| <selector refid="not.in.kaffe" if="kaffe"/> | <selector refid="not.in.kaffe" if="kaffe"/> | ||||
| <selector refid="needs.apache-resolver" unless="apache.resolver.present"/> | <selector refid="needs.apache-resolver" unless="apache.resolver.present"/> | ||||
| <selector refid="needs.junit" unless="junit.present"/> <!-- TODO should perhaps use -source 1.4? --> | <selector refid="needs.junit" unless="junit.present"/> <!-- TODO should perhaps use -source 1.4? --> | ||||
| @@ -26,9 +26,14 @@ | |||||
| <p><em>This task has been <u>deprecated</u>. Use a <a href="../Types/zipfileset.html">zipfileset</a> | <p><em>This task has been <u>deprecated</u>. Use a <a href="../Types/zipfileset.html">zipfileset</a> | ||||
| or <a href="../Tasks/zip.html#zipgroupfileset">zipgroupfileset</a> with | or <a href="../Tasks/zip.html#zipgroupfileset">zipgroupfileset</a> with | ||||
| the <a href="../Tasks/jar.html">Jar task</a> or <a href="../Tasks/zip.html">Zip task</a> | the <a href="../Tasks/jar.html">Jar task</a> or <a href="../Tasks/zip.html">Zip task</a> | ||||
| instead.</em></p> | |||||
| instead. For a task based on the JDK's jlink tool, see | |||||
| <a href="link.html">Link</a>.</em></p> | |||||
| <h3>Description</h3> | <h3>Description</h3> | ||||
| <p><strong>For a task based on the JDK's jlink tool, see | |||||
| <a href="link.html">Link</a>. This task is for something else | |||||
| entirely.</strong></p> | |||||
| <p>Links entries from sub-builds and libraries.</p> | <p>Links entries from sub-builds and libraries.</p> | ||||
| <p>The <code>jlink</code> task can be used to build jar and zip files, similar to | <p>The <code>jlink</code> task can be used to build jar and zip files, similar to | ||||
| @@ -0,0 +1,330 @@ | |||||
| <!-- | |||||
| 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 | |||||
| http://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> | |||||
| <head> | |||||
| <meta http-equiv="Content-Language" content="en-us"> | |||||
| <link rel="stylesheet" type="text/css" href="../stylesheets/style.css"> | |||||
| <title>Jmod Task</title> | |||||
| </head> | |||||
| <body> | |||||
| <h2 id="jmod">Jmod</h2> | |||||
| <h3>Description</h3> | |||||
| <p>Creates a linkable jmod file from a modular jar file, and optionally from | |||||
| other application files such as native libraries and license documents. | |||||
| Equivalent to the JDK's | |||||
| <a href="https://docs.oracle.com/en/java/javase/11/tools/jmod.html">jmod</a> | |||||
| tool.</p> | |||||
| <p>Requires Java 9 or later.</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>destFile</td> | |||||
| <td>jmod file to create.</td> | |||||
| <td>Yes</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>classpath</td> | |||||
| <td>Files to be placed in the jmod file. Usually a single module.</td> | |||||
| <td rowspan="2">One of these is required, unless a nested | |||||
| <code><classpath></code> is present.</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>classpathref</td> | |||||
| <td class="left">Files to be placed in the jmod file, given as a | |||||
| <a href="../using.html#references">reference</a> | |||||
| to a path defined elsewhere.</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>modulepath</td> | |||||
| <td>Locations of modules on which classpath modules depend.</td> | |||||
| <td>No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>modulepathref</td> | |||||
| <td>Locations of modules on which classpath modules depend, | |||||
| given as a <a href="../using.html#references">reference</a> | |||||
| to a path defined elsewhere.</td> | |||||
| <td>No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>commandpath</td> | |||||
| <td>Directories containing native commands to include in jmod.</td> | |||||
| <td>No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>commandpathref</td> | |||||
| <td>Directories containing native commands to include in jmod, | |||||
| given as a <a href="../using.html#references">reference</a> | |||||
| to a path defined elsewhere.</td> | |||||
| <td>No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>headerpath</td> | |||||
| <td>Directories containing header files to include in jmod.</td> | |||||
| <td>No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>headerpathref</td> | |||||
| <td>Directories containing header files to include in jmod, | |||||
| given as a <a href="../using.html#references">reference</a> | |||||
| to a path defined elsewhere.</td> | |||||
| <td>No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>configpath</td> | |||||
| <td>Directories containing user-editable configuration files | |||||
| to include in jmod.</td> | |||||
| <td>No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>configpathref</td> | |||||
| <td>Directories containing user-editable configuration files | |||||
| to include in jmod, | |||||
| given as a <a href="../using.html#references">reference</a> | |||||
| to a path defined elsewhere.</td> | |||||
| <td>No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>legalpath</td> | |||||
| <td>Directories containing legal licenses and notices to include in jmod.</td> | |||||
| <td>No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>legalpathref</td> | |||||
| <td>Directories containing legal licenses and notices to include in jmod, | |||||
| given as a <a href="../using.html#references">reference</a> | |||||
| to a path defined elsewhere.</td> | |||||
| <td>No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>nativelibpath</td> | |||||
| <td>Directories containing native libraries to include in jmod.</td> | |||||
| <td>No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>nativelibpathref</td> | |||||
| <td>Directories containing native libraries to include in jmod, | |||||
| given as a <a href="../using.html#references">reference</a> | |||||
| to a path defined elsewhere.</td> | |||||
| <td>No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>manpath</td> | |||||
| <td>Directories containing man pages to include in jmod.</td> | |||||
| <td>No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>manpathref</td> | |||||
| <td>Directories containing man pages to include in jmod, | |||||
| given as a <a href="../using.html#references">reference</a> | |||||
| to a path defined elsewhere.</td> | |||||
| <td>No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>version</td> | |||||
| <td><a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/module/ModuleDescriptor.Version.html">Module version</a> of jmod.</td> | |||||
| <td>No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>mainclass</td> | |||||
| <td>Class that acts as executable entry point of module.</td> | |||||
| <td>No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>platform</td> | |||||
| <td>The target platform for the jmod. Typically takes the form | |||||
| <var>OS</var><code>-</code><var>architecture</var>. A particular JDK's | |||||
| platform can be seen by running a command like | |||||
| <samp>jmod describe $JDK_HOME/jmods/java.base.jmod | grep -i platform</samp></td> | |||||
| <td>No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>hashModulesPattern</td> | |||||
| <td>Regular expression for names of modules in the module path | |||||
| which depend on the jmod being created, and which should have | |||||
| hashes generated for them and included in the new jmod.</td> | |||||
| <td>No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>resolveByDefault</td> | |||||
| <td>Boolean indicating whether the jmod should be one of | |||||
| the default resolved modules when it is in a module path | |||||
| searched by tools and applications.</td> | |||||
| <td>No. Default is true.</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>moduleWarnings</td> | |||||
| <td>Whether to emit warnings when resolving modules which are | |||||
| not recommended for use. Comma-separated list of one of more of | |||||
| the following: | |||||
| <dl> | |||||
| <dt><code>deprecated</code></dt> | |||||
| <dd>Warn if module is deprecated</dd> | |||||
| <dt><code>leaving</code></dt> | |||||
| <dd>Warn if module is deprecated for removal</dd> | |||||
| <dt><code>incubating</code></dt> | |||||
| <dd>Warn if module is an incubating (not yet official) module</dd> | |||||
| </dl> | |||||
| </td> | |||||
| <td>No, default is no warnings.</td> | |||||
| </tr> | |||||
| </table> | |||||
| <h3>Parameters specified as nested elements</h3> | |||||
| <h4>classpath, modulepath, commandpath, headerpath, configpath, legalpath, nativelibpath, manpath</h4> | |||||
| <p>The | |||||
| <code>classpath</code>, | |||||
| <code>modulepath</code>, | |||||
| <code>commandpath</code>, | |||||
| <code>headerpath</code>, | |||||
| <code>configpath</code>, | |||||
| <code>legalpath</code>, | |||||
| <code>nativelibpath</code>, and | |||||
| <code>manpath</code> | |||||
| attributes are <a href="../using.html#path">path-like structures</a> | |||||
| and can also be set via nested | |||||
| <code><classpath></code>, | |||||
| <code><modulepath></code>, | |||||
| <code><commandpath></code>, | |||||
| <code><headerpath></code>, | |||||
| <code><configpath></code>, | |||||
| <code><legalpath></code>, | |||||
| <code><nativelibpath></code>, and | |||||
| <code><manpath></code> | |||||
| elements, respectively.</p> | |||||
| <h4>version</h4> | |||||
| <p>Fine-grained alternative to the <code>version</code> attribute. This | |||||
| nested element has these attributes:</p> | |||||
| <table class="attr"> | |||||
| <tr> | |||||
| <th scope="col">Attribute</th> | |||||
| <th scope="col">Description</th> | |||||
| <th scope="col">Required</th> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>number</td> | |||||
| <td>Primary version number. Can be any text, as long as it does not | |||||
| contain a hyphen (<code>-</code>) or plus (<code>+</code>).</td> | |||||
| <td>Yes</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>preRelease</td> | |||||
| <td>Pre-release version. Can be any text, as long as it does not | |||||
| contain a plus (<code>+</code>).</td> | |||||
| <td>No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>build</td> | |||||
| <td>Build version. Can be any text. | |||||
| <td>No</td> | |||||
| </tr> | |||||
| </table> | |||||
| <p>See the <a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/module/ModuleDescriptor.Version.html">ModuleDescriptor.Version documentation</a> | |||||
| for a full description of the meaning of each version component.</p> | |||||
| <h4>moduleWarning</h4> | |||||
| <p>Like the <code>moduleWarnings</code> attribute, but only specifies a single | |||||
| basis for emitting warnings. This child element may appear multiple times, | |||||
| to specify multiple conditions under which warnings should be emitted by the | |||||
| jmod tool.</p> | |||||
| <p>Attributes:</p> | |||||
| <table class="attr"> | |||||
| <tr> | |||||
| <th scope="col">Attribute</th> | |||||
| <th scope="col">Description</th> | |||||
| <th scope="col">Required</th> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>reason</td> | |||||
| <td>Condition which will cause jmod tool to emit warnings. One of: | |||||
| <dl> | |||||
| <dt><code>deprecated</code></dt> | |||||
| <dd>Warn if module is deprecated</dd> | |||||
| <dt><code>leaving</code></dt> | |||||
| <dd>Warn if module is deprecated for removal</dd> | |||||
| <dt><code>incubating</code></dt> | |||||
| <dd>Warn if module is an incubating (not yet official) module</dd> | |||||
| </dl> | |||||
| <td>Yes</td> | |||||
| </tr> | |||||
| </table> | |||||
| <h3>Examples</h3> | |||||
| <h4>Basic jmod</h4> | |||||
| <p>Create a jmod from a single modular jar file:</p> | |||||
| <pre> | |||||
| <jmod destfile="MyApp.jmod" classpath="build/myapp.jar"/> | |||||
| </pre> | |||||
| <h4>With dependencies</h4> | |||||
| <p>Create a jmod from a modular jar file which depends on another module:</p> | |||||
| <pre> | |||||
| <jmod destfile="MyApp.jmod" classpath="build/myapp.jar"> | |||||
| <modulepath> | |||||
| <pathelement location="libs/thirdpartyutils.jar"/> | |||||
| </modulepath> | |||||
| </jmod> | |||||
| </pre> | |||||
| <h4>With version</h4> | |||||
| <p>Create a jmod with a module version:</p> | |||||
| <pre> | |||||
| <jmod destfile="MyApp.jmod" classpath="build/myapp.jar" | |||||
| version="1.2.1-ea+29"/> | |||||
| </pre> | |||||
| <p>Create a versioned jmod from module version components:</p> | |||||
| <pre> | |||||
| <property name="version" value="1.2.1"/> | |||||
| <buildnumber/> | |||||
| <loadfile property="buildnum" srcFile="build.number"/> | |||||
| <jmod destfile="MyApp.jmod" classpath="build/myapp.jar"> | |||||
| <version number="${version}" build="${buildnum}"/> | |||||
| </jmod> | |||||
| </pre> | |||||
| <h4>Main class</h4> | |||||
| <p>Create a jmod with a main class:</p> | |||||
| <pre> | |||||
| <jmod destfile="MyApp.jmod" classpath="build/myapp.jar" | |||||
| mainclass="com.example.myapp.MainWindow"/> | |||||
| </pre> | |||||
| <h4>Target platform</h4> | |||||
| <p>Create a jmod for a specific platform, possibly different from the | |||||
| current platform:</p> | |||||
| <pre> | |||||
| <jmod destfile="MyApp.jmod" classpath="build/myapp.jar" | |||||
| platform="windows-amd64"/> | |||||
| </pre> | |||||
| </body> | |||||
| </html> | |||||
| @@ -0,0 +1,579 @@ | |||||
| <!-- | |||||
| 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 | |||||
| http://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> | |||||
| <head> | |||||
| <meta http-equiv="Content-Language" content="en-us"> | |||||
| <link rel="stylesheet" type="text/css" href="../stylesheets/style.css"> | |||||
| <title>Link Task</title> | |||||
| </head> | |||||
| <body> | |||||
| <h2 id="link">Link</h2> | |||||
| <h3>Description</h3> | |||||
| <p>Assembles jmod files into an executable image. Equivalent to the JDK's | |||||
| <a href="https://docs.oracle.com/en/java/javase/11/tools/jlink.html">jlink</a> | |||||
| tool. | |||||
| </p> | |||||
| <p>Requires Java 9 or later.</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>destDir</td> | |||||
| <td>Root directory of created image.</td> | |||||
| <td>Yes</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>modulepath</td> | |||||
| <td>Path-like sequence of jmod files to link in order to create image.</td> | |||||
| <td rowspan="2">One of these is required, unless a nested | |||||
| <code><modulepath></code> is present.</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>modulepathref</td> | |||||
| <td class="left">Path-like sequence of jmod files to link in order to | |||||
| create image, given as a <a href="../using.html#references">reference</a> | |||||
| to a path defined elsewhere.</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>modules</td> | |||||
| <td>Comma-separated list of modules to place in the linked image.</td> | |||||
| <td>Yes, unless one or more nested <code><module></code> elements | |||||
| are present.</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>observableModules</td> | |||||
| <td>Comma-separated list of explicit modules that comprise | |||||
| "universe" visible to link tool while linking.</td> | |||||
| <td>No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>launchers</td> | |||||
| <td>Comma-separated list of commands, each of the form | |||||
| <var>name</var><code>=</code><var>module</var> or | |||||
| <var>name</var><code>=</code><var>module</var><code>/</code><var>mainclass</var></td> | |||||
| <td>No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>locales</td> | |||||
| <td>Comma-separated list of extra locales, or wildcard patterns matching | |||||
| multiple locale names, to include. | |||||
| Requires <code>jdk.localedata</code> module.</td> | |||||
| <td>No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>excludeResources</td> | |||||
| <td>Comma-separated list of patterns specifying resources to exclude | |||||
| from source jmods. Each is either a | |||||
| <a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/file/FileSystem.html#getPathMatcher%28java.lang.String%29">standard PathMatcher pattern</a> | |||||
| or <code>@</code><var>filename</var>, indicating a text file with | |||||
| one resource name per line.</td> | |||||
| <td>No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>excludeFiles</td> | |||||
| <td>Comma-separated list of patterns specifying files to exclude | |||||
| from linked image. Each is either a | |||||
| <a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/file/FileSystem.html#getPathMatcher%28java.lang.String%29">standard PathMatcher pattern</a> | |||||
| or <code>@</code><var>filename</var>, indicating a text file with | |||||
| one file name per line.</td> | |||||
| <td>No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>resourceOrder</td> | |||||
| <td>Comma-separated list of patterns specifying resource search order. | |||||
| Each is either a | |||||
| <a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/file/FileSystem.html#getPathMatcher%28java.lang.String%29">standard PathMatcher pattern</a> | |||||
| or <code>@</code><var>filename</var>, indicating a text file with | |||||
| one resource name per line.</td> | |||||
| <td>No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>bindServices</td> | |||||
| <td>Boolean, whether to include in linked image any service providers | |||||
| found in module path corresponding to service provider interfaces | |||||
| used by explicitly linked modules.</td> | |||||
| <td>No, default is false</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>ignoreSigning</td> | |||||
| <td>Boolean, whether to allow signed jar files. | |||||
| (Note: As of Java 11, this is ignored and is always treated as true.)</td> | |||||
| <td>No, default is false</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>includeHeaders</td> | |||||
| <td>Boolean, whether to include header files in linked image.</td> | |||||
| <td>No, default is true</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>includeManPages</td> | |||||
| <td>Boolean, whether to include man pages in linked image.</td> | |||||
| <td>No, default is true</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>includeNativeCommands</td> | |||||
| <td>Boolean, whether to include native executables in linked image.</td> | |||||
| <td>No, default is true</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>debug</td> | |||||
| <td>Boolean, whether to include debug information.</td> | |||||
| <td>No, default is true</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>verboseLevel</td> | |||||
| <td>If set, the linker will produce verbose output, which will be logged at | |||||
| the specified Ant log level (<code>DEBUG</code>, <code>VERBOSE</code>, | |||||
| <code>INFO</code>, <code>WARN</code>, or <code>ERR</code>).</td> | |||||
| <td>No, default is no verbose output</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>compress</td> | |||||
| <td>Compression level of linked image. One of: | |||||
| <dl> | |||||
| <dt><code>0</code> or | |||||
| <code>none</code></dt> | |||||
| <dd>no compression (default)</dd> | |||||
| <dt><code>1</code> or | |||||
| <code>strings</code></dt> | |||||
| <dd>constant string sharing</dd> | |||||
| <dt><code>2</code> or | |||||
| <code>zip</code></dt> | |||||
| <dd>zip compression</dd> | |||||
| </dl> | |||||
| </td> | |||||
| <td>No, default is no compression</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>endianness</td> | |||||
| <td>Byte order of linked image, must be <code>little</code> or <code>big</code> | |||||
| <td>No, default is native byte order</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>checkDuplicateLegal</td> | |||||
| <td>Boolean. When merging legal notices from different modules | |||||
| because they have the same name, verify that their contents | |||||
| are identical.</td> | |||||
| <td>No, default is false, which means any license files | |||||
| with the same name are assumed to have the same content, and no | |||||
| checking is done.</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>vmType</td> | |||||
| <td>Hotspot VM in image. One of: | |||||
| <ul> | |||||
| <li><code>client</code> | |||||
| <li><code>server</code> | |||||
| <li><code>minimal</code> | |||||
| <li><code>all</code> | |||||
| </ul> | |||||
| </td> | |||||
| <td>No, default is <code>all</code></td> | |||||
| </tr> | |||||
| </table> | |||||
| <h3>Parameters specified as nested elements</h3> | |||||
| <p><code><link></code> can have the following nested elements:</p> | |||||
| <ul> | |||||
| <li><a href="#nested-modulepath">modulepath</a></li> | |||||
| <li><a href="#nested-module">module</a></li> | |||||
| <li><a href="#nested-observableModule">observableModule</a></li> | |||||
| <li><a href="#nested-launcher">launcher</a></li> | |||||
| <li><a href="#nested-locale">locale</a></li> | |||||
| <li><a href="#nested-resourceOrder">resourceOrder</a></li> | |||||
| <li><a href="#nested-excludeResources">excludeResources</a></li> | |||||
| <li><a href="#nested-excludeFiles">excludeFiles</a></li> | |||||
| <li><a href="#nested-compress">compress</a></li> | |||||
| <li><a href="#nested-releaseInfo">releaseInfo</a></li> | |||||
| </ul> | |||||
| <h4 id="nested-modulepath">modulepath</h4> | |||||
| <p><a href="../using.html#path">Path-like structure</a> pointing to | |||||
| jmod files to link into image.</p> | |||||
| <h4 id="nested-module">module</h4> | |||||
| <p>Names a single module to be placed in the linked image. This may be | |||||
| specified multiple times.</p> | |||||
| <p>Attributes:</p> | |||||
| <table class="attr"> | |||||
| <tr> | |||||
| <th scope="col">Attribute</th> | |||||
| <th scope="col">Description</th> | |||||
| <th scope="col">Required</th> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>name</td> | |||||
| <td>Name of module to add.</td> | |||||
| <td>Yes</td> | |||||
| </tr> | |||||
| </table> | |||||
| <h4 id="nested-observableModule">observableModule</h4> | |||||
| <p>Names a module visible to the linking process, instead of every module | |||||
| in the module path being considered. This may be specified multiple times. | |||||
| <p>Attributes:</p> | |||||
| <table class="attr"> | |||||
| <tr> | |||||
| <th scope="col">Attribute</th> | |||||
| <th scope="col">Description</th> | |||||
| <th scope="col">Required</th> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>name</td> | |||||
| <td>Name of module to add to list of observable modules.</td> | |||||
| <td>Yes</td> | |||||
| </tr> | |||||
| </table> | |||||
| <h4 id="nested-launcher">launcher</h4> | |||||
| <p>Specifies an executable file which will be added to the linked image, | |||||
| which executes a particular module's main class. Attributes:</p> | |||||
| <table class="attr"> | |||||
| <tr> | |||||
| <th scope="col">Attribute</th> | |||||
| <th scope="col">Description</th> | |||||
| <th scope="col">Required</th> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>name</td> | |||||
| <td>Name of launcher. This typically is used for the name of the | |||||
| executable file.</td> | |||||
| <td>Yes</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>module</td> | |||||
| <td>Name of module to execute.</td> | |||||
| <td>Yes</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>mainClass</td> | |||||
| <td>Name of entry point class in module to execute.</td> | |||||
| <td>Required unless module has its own main class defined.</td> | |||||
| </tr> | |||||
| </table> | |||||
| <h4 id="nested-locale">locale</h4> | |||||
| <p>Specifies locales to include in linked image. May be specified multiple | |||||
| times. Requires <code>jdk.localedata</code> module. Attributes: | |||||
| <table class="attr"> | |||||
| <tr> | |||||
| <th scope="col">Attribute</th> | |||||
| <th scope="col">Description</th> | |||||
| <th scope="col">Required</th> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>name</td> | |||||
| <td>Name of locale, or wildcard pattern with <q><code>*</code></q> | |||||
| that matches multiple locale names.</td> | |||||
| <td>Yes</td> | |||||
| </tr> | |||||
| </table> | |||||
| <h4 id="nested-resourceOrder">resourceOrder</h4> | |||||
| <p>Explicit resource search order in linked image. May be specified multiple | |||||
| times. Attributes:</p> | |||||
| <table class="attr"> | |||||
| <tr> | |||||
| <th scope="col">Attribute</th> | |||||
| <th scope="col">Description</th> | |||||
| <th scope="col">Required</th> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>pattern</td> | |||||
| <td>A <a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/file/FileSystem.html#getPathMatcher%28java.lang.String%29">standard PathMatcher pattern</a> | |||||
| for matching resources</td> | |||||
| <td rowspan="2">Exactly one of these</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>listFile</td> | |||||
| <td class="left">Text file containing list of resource names (not patterns), | |||||
| one per line</td> | |||||
| </tr> | |||||
| </table> | |||||
| <p>If the <code>resourceOrder</code> attribute is also present on the task, its | |||||
| patterns are treated as if they occur before patterns in nested | |||||
| <code><resourceOrder></code> elements.</p> | |||||
| <h4 id="nested-excludeResources">excludeResources</h4> | |||||
| <p>Excludes files from linked image tree. May be specified multiple times. | |||||
| Attributes:</p> | |||||
| <table class="attr"> | |||||
| <tr> | |||||
| <th scope="col">Attribute</th> | |||||
| <th scope="col">Description</th> | |||||
| <th scope="col">Required</th> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>pattern</td> | |||||
| <td>A <a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/file/FileSystem.html#getPathMatcher%28java.lang.String%29">standard PathMatcher pattern</a> | |||||
| for matching resources</td> | |||||
| <td rowspan="2">Exactly one of these</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>listFile</td> | |||||
| <td class="left">Text file containing list of resource names (not patterns), | |||||
| one per line</td> | |||||
| </tr> | |||||
| </table> | |||||
| <h4 id="nested-excludeFiles">excludeFiles</h4> | |||||
| <p>Excludes files from linked image. May be specified multiple times. | |||||
| Attributes:</p> | |||||
| <table class="attr"> | |||||
| <tr> | |||||
| <th scope="col">Attribute</th> | |||||
| <th scope="col">Description</th> | |||||
| <th scope="col">Required</th> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>pattern</td> | |||||
| <td>A <a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/file/FileSystem.html#getPathMatcher%28java.lang.String%29">standard PathMatcher pattern</a> | |||||
| for matching files</td> | |||||
| <td rowspan="2">Exactly one of these</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>listFile</td> | |||||
| <td class="left">Text file containing list of file names (not patterns), | |||||
| one per line</td> | |||||
| </tr> | |||||
| </table> | |||||
| <h4 id="nested-compress">compress</h4> | |||||
| <p>Describes how image should be compressed. Attributes:</p> | |||||
| <table class="attr"> | |||||
| <tr> | |||||
| <th scope="col">Attribute</th> | |||||
| <th scope="col">Description</th> | |||||
| <th scope="col">Required</th> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>level</td> | |||||
| <td>Compression level of linked image. One of: | |||||
| <dl> | |||||
| <dt><code>0</code> or | |||||
| <code>none</code></dt> | |||||
| <dd>no compression (default)</dd> | |||||
| <dt><code>1</code> or | |||||
| <code>strings</code></dt> | |||||
| <dd>constant string sharing</dd> | |||||
| <dt><code>2</code> or | |||||
| <code>zip</code></dt> | |||||
| <dd>zip compression</dd> | |||||
| </dl> | |||||
| </td> | |||||
| <td>Yes</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>files</td> | |||||
| <td>Comma-separated list of patterns matching files to compress. | |||||
| Each pattern either a | |||||
| <a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/file/FileSystem.html#getPathMatcher%28java.lang.String%29">standard PathMatcher pattern</a> | |||||
| or <code>@</code><var>filename</var>, indicating a text file with | |||||
| one file name per line.</td> | |||||
| <td>No</td> | |||||
| </tr> | |||||
| </table> | |||||
| <p><code><compress></code> can also have any number of nested | |||||
| <code><files></code> elements, with these attributes:</p> | |||||
| <table class="attr"> | |||||
| <tr> | |||||
| <th scope="col">Attribute</th> | |||||
| <th scope="col">Description</th> | |||||
| <th scope="col">Required</th> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>pattern</td> | |||||
| <td>A <a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/file/FileSystem.html#getPathMatcher%28java.lang.String%29">standard PathMatcher pattern</a> | |||||
| for matching files</td> | |||||
| <td rowspan="2">Exactly one of these</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>listFile</td> | |||||
| <td class="left">Text file containing list of file names (not patterns), | |||||
| one per line</td> | |||||
| </tr> | |||||
| </table> | |||||
| <h4 id="nested-releaseInfo">releaseInfo</h4> | |||||
| <p>Replaces, augments, or trims the image's release info properties. | |||||
| Can be specified multiple times. Attributes: | |||||
| <table class="attr"> | |||||
| <tr> | |||||
| <th scope="col">Attribute</th> | |||||
| <th scope="col">Description</th> | |||||
| <th scope="col">Required</th> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>file</td> | |||||
| <td>Java properties file containing new release info properties | |||||
| that will entirely replace the current ones.</td> | |||||
| <td>No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>delete</td> | |||||
| <td>Comma-separated property keys to remove from application's | |||||
| release info | |||||
| <td>No</td> | |||||
| </tr> | |||||
| </table> | |||||
| <p><code><releaseInfo></code> can also have any number of these nested elements:</p> | |||||
| <h5>add</h5> | |||||
| <p>Specifies additional release info properties. Attributes:</p> | |||||
| <table class="attr"> | |||||
| <tr> | |||||
| <th scope="col">Attribute</th> | |||||
| <th scope="col">Description</th> | |||||
| <th scope="col">Required</th> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>key</td> | |||||
| <td>Key of single property to add.</td> | |||||
| <td rowspan="2">Yes, unless <code>file</code> is specified</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>value</td> | |||||
| <td class="left">Value of single property to add.</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>file</td> | |||||
| <td>Java property file containing any number of properties to add.</td> | |||||
| <td>Yes, unless <code>key</code> and <code>value</code> are specified</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>charset</td> | |||||
| <td>Character set of property file.</td> | |||||
| <td>No, default is <code>ISO_8859_1</code>, in accordance with | |||||
| java.util.Properties class.</td> | |||||
| </tr> | |||||
| </table> | |||||
| <h5>delete</h5> | |||||
| <p>Property keys to remove from applicaiton's release info. Attributes:</p> | |||||
| <table class="attr"> | |||||
| <tr> | |||||
| <th scope="col">Attribute</th> | |||||
| <th scope="col">Description</th> | |||||
| <th scope="col">Required</th> | |||||
| </tr> | |||||
| <tr> | |||||
| <td>key</td> | |||||
| <td>Key of property to remove.</td> | |||||
| <td>Yes</td> | |||||
| </tr> | |||||
| </table> | |||||
| <h3>Examples</h3> | |||||
| <h4>Basic linking</h4> | |||||
| <pre> | |||||
| <jmod destfile="MyApp.jmod" classpath="build/myapp.jar"/> | |||||
| <link destDir="build/image" modulepath="MyApp.jmod" | |||||
| modules="com.example.myapp"/> | |||||
| </pre> | |||||
| <h4>Custom binaries</h4> | |||||
| <p>This will cause a <samp>bin/MyEditor</samp> script to appear in the | |||||
| image: | |||||
| <pre> | |||||
| <jmod destfile="MyApp.jmod" classpath="build/myapp.jar"/> | |||||
| <link destDir="build/image" modulepath="MyApp.jmod" | |||||
| modules="com.example.myapp" | |||||
| launchers="MyEditor=com.example.myapp/com.example.myapp.editors.EditorMain"/> | |||||
| </pre> | |||||
| <p>Same thing, using a nested launcher element:</p> | |||||
| <pre> | |||||
| <jmod destfile="MyApp.jmod" classpath="build/myapp.jar"/> | |||||
| <link destDir="build/image" modulepath="MyApp.jmod" | |||||
| modules="com.example.myapp"> | |||||
| <launcher name="MyEditor" module="com.example.myapp" | |||||
| mainClass="com.example.myapp.editors.EditorMain"/> | |||||
| </link> | |||||
| </pre> | |||||
| <h4>Limiting locales</h4> | |||||
| <p>Include just the locales needed by the application from the <a href="https://docs.oracle.com/en/java/javase/11/docs/api/jdk.localedata/module-summary.html">jdk.localedata</a> module:</p> | |||||
| <pre> | |||||
| <jmod destfile="MyApp.jmod" classpath="build/myapp.jar"/> | |||||
| <link destDir="build/image" modulepath="MyApp.jmod" | |||||
| modules="com.example.myapp,jdk.localedata" | |||||
| locales="zh,jp-*"/> | |||||
| </pre> | |||||
| <h4>Compressed image</h4> | |||||
| <p>Compress entire image:</p> | |||||
| <pre> | |||||
| <jmod destfile="MyApp.jmod" classpath="build/myapp.jar"/> | |||||
| <link destDir="build/image" modulepath="MyApp.jmod" | |||||
| modules="com.example.myapp,jdk.localedata" | |||||
| compress="zip"/> | |||||
| </pre> | |||||
| <p>Compress only some files in the image:</p> | |||||
| <pre> | |||||
| <jmod destfile="MyApp.jmod" classpath="build/myapp.jar"/> | |||||
| <link destDir="build/image" modulepath="MyApp.jmod" | |||||
| modules="com.example.myapp,jdk.localedata"> | |||||
| <compress level="zip" files=".*\.xml"/> | |||||
| </link> | |||||
| </pre> | |||||
| <h4>Cross-compiling</h4> | |||||
| <p>To create an image for a different platform: | |||||
| <ul> | |||||
| <li>Download the JDK for that platform, and expand the archive manually into | |||||
| a directory of your choice. (Downloading a zip or tar.gz version of a JDK | |||||
| instead of an installer will make this easier.)</li> | |||||
| <li>Determine the foreign JDK's platform string. This can be done with | |||||
| a command that examines the JDK's <samp>jmods/java.base.jmod</samp> file: | |||||
| <pre> | |||||
| jmod describe "$FOREIGN_JDK_HOME"/jmods/java.base.jmod | grep '^platform' | |||||
| </pre> | |||||
| </li> | |||||
| <li>Create your jmod using the foreign JDK's platform string: | |||||
| <pre> | |||||
| <jmod destfile="MyApp.jmod" classpath="build/myapp.jar" platform="windows-amd64"/> | |||||
| </pre> | |||||
| </li> | |||||
| <li>Link with the foreign JDK's <samp>jmods</samp> directory in the module path: | |||||
| <pre> | |||||
| <link destDir="build/image" | |||||
| modulepath="MyApp.jmod;${foreign-jdk-home}/jmods" | |||||
| modules="com.example.myapp"/> | |||||
| </pre> | |||||
| </li> | |||||
| </ul> | |||||
| <ul> | |||||
| </body> | |||||
| </html> | |||||
| @@ -108,11 +108,13 @@ | |||||
| <li><a href="Tasks/jjdoc.html">JJDoc</a></li> | <li><a href="Tasks/jjdoc.html">JJDoc</a></li> | ||||
| <li><a href="Tasks/jjtree.html">JJTree</a></li> | <li><a href="Tasks/jjtree.html">JJTree</a></li> | ||||
| <li><a href="Tasks/jlink.html"><em>Jlink</em></a></li> | <li><a href="Tasks/jlink.html"><em>Jlink</em></a></li> | ||||
| <li><a href="Tasks/jmod.html">Jmod</a></li> | |||||
| <li><a href="Tasks/jspc.html"><em>JspC</em></a></li> | <li><a href="Tasks/jspc.html"><em>JspC</em></a></li> | ||||
| <li><a href="Tasks/junit.html">JUnit</a> (3 & 4)</li> | <li><a href="Tasks/junit.html">JUnit</a> (3 & 4)</li> | ||||
| <li><a href="Tasks/junitlauncher.html">JUnitLauncher</a> (JUnit 5)</li> | <li><a href="Tasks/junitlauncher.html">JUnitLauncher</a> (JUnit 5)</li> | ||||
| <li><a href="Tasks/junitreport.html">JUnitReport</a></li> | <li><a href="Tasks/junitreport.html">JUnitReport</a></li> | ||||
| <li><a href="Tasks/length.html">Length</a><br/></li> | <li><a href="Tasks/length.html">Length</a><br/></li> | ||||
| <li><a href="Tasks/link.html">Link</a><br/></li> | |||||
| <li><a href="Tasks/loadfile.html">LoadFile</a></li> | <li><a href="Tasks/loadfile.html">LoadFile</a></li> | ||||
| <li><a href="Tasks/loadproperties.html">LoadProperties</a></li> | <li><a href="Tasks/loadproperties.html">LoadProperties</a></li> | ||||
| <li><a href="Tasks/loadresource.html">LoadResource</a></li> | <li><a href="Tasks/loadresource.html">LoadResource</a></li> | ||||
| @@ -121,7 +121,7 @@ | |||||
| destfile="${tmp.jar}" | destfile="${tmp.jar}" | ||||
| basedir="." | basedir="." | ||||
| includes="j*.xml" | includes="j*.xml" | ||||
| excludes="java.xml" | |||||
| excludes="java.xml,jmod.xml" | |||||
| update="true" | update="true" | ||||
| /> | /> | ||||
| </target> | </target> | ||||
| @@ -131,7 +131,7 @@ | |||||
| destfile="${tmp.jar}" | destfile="${tmp.jar}" | ||||
| basedir="." | basedir="." | ||||
| includes="j*.xml" | includes="j*.xml" | ||||
| excludes="java.xml" | |||||
| excludes="java.xml,jmod.xml" | |||||
| /> | /> | ||||
| </target> | </target> | ||||
| @@ -144,14 +144,14 @@ | |||||
| depends="makezip"> | depends="makezip"> | ||||
| <jar destfile="${tmp.jar}" | <jar destfile="${tmp.jar}" | ||||
| update="true"> | update="true"> | ||||
| <zipfileset src="${tmp.zip}" excludes="java.xml"/> | |||||
| <zipfileset src="${tmp.zip}" excludes="java.xml,jmod.xml"/> | |||||
| </jar> | </jar> | ||||
| </target> | </target> | ||||
| <target name="testNoRecreateZipfilesetExcludesWithoutUpdate" | <target name="testNoRecreateZipfilesetExcludesWithoutUpdate" | ||||
| depends="makezip"> | depends="makezip"> | ||||
| <jar destfile="${tmp.jar}"> | <jar destfile="${tmp.jar}"> | ||||
| <zipfileset src="${tmp.zip}" excludes="java.xml"/> | |||||
| <zipfileset src="${tmp.zip}" excludes="java.xml,jmod.xml"/> | |||||
| </jar> | </jar> | ||||
| </target> | </target> | ||||
| @@ -0,0 +1,992 @@ | |||||
| <?xml version="1.0"?> | |||||
| <!-- | |||||
| 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 | |||||
| http://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. | |||||
| --> | |||||
| <project name="jmodtest" default="nil" > | |||||
| <import file="../buildfiletest-base.xml"/> | |||||
| <target name="nil"/> | |||||
| <target name="-dirs"> | |||||
| <mkdir dir="${input}"/> | |||||
| <mkdir dir="${output}"/> | |||||
| <property name="jmod" value="${output}/test.jmod"/> | |||||
| <property name="version" value="1.0.1-+99"/> | |||||
| </target> | |||||
| <target name="setUp" depends="-dirs"> | |||||
| </target> | |||||
| <!-- Creates simple modular jar, with only Java SE dependencies. --> | |||||
| <target name="-hello" depends="-dirs"> | |||||
| <property name="hello.root" value="${input}/hello"/> | |||||
| <property name="hello.src" value="${hello.root}/src"/> | |||||
| <property name="hello.classes" value="${hello.root}/classes"/> | |||||
| <property name="hello.jar.dir" value="${hello.root}/jars"/> | |||||
| <property name="hello.jar" value="${hello.jar.dir}/hello.jar"/> | |||||
| <property name="hello.pkg" value= "org.apache.tools.ant.test.hello"/> | |||||
| <property name="hello.pkg.dir" value="${hello.src}/org/apache/tools/ant/test/hello"/> | |||||
| <property name="hello.main-class" value="${hello.pkg}.HelloWorld"/> | |||||
| <mkdir dir="${hello.pkg.dir}"/> | |||||
| <echo file="${hello.pkg.dir}/HelloWorld.java"> | |||||
| package ${hello.pkg}; | |||||
| import java.util.logging.Logger; | |||||
| public class HelloWorld { | |||||
| public void run() { | |||||
| Logger logger = Logger.getLogger(HelloWorld.class.getName()); | |||||
| logger.info("HELLO WORLD"); | |||||
| } | |||||
| public static void main(String[] args) { | |||||
| new HelloWorld().run(); | |||||
| } | |||||
| } | |||||
| </echo> | |||||
| <echo file="${hello.src}/module-info.java"> | |||||
| module ${hello.pkg} { | |||||
| exports ${hello.pkg}; | |||||
| requires java.logging; | |||||
| } | |||||
| </echo> | |||||
| <mkdir dir="${hello.classes}"/> | |||||
| <javac srcdir="${hello.src}" destdir="${hello.classes}" includeAntRuntime="false"/> | |||||
| <mkdir dir="${hello.jar.dir}"/> | |||||
| <jar destfile="${hello.jar}" basedir="${hello.classes}"/> | |||||
| </target> | |||||
| <!-- Creates modular jar with dependency on hello module. --> | |||||
| <target name="-smile" depends="-dirs,-hello"> | |||||
| <property name="smile.root" value="${input}/smile"/> | |||||
| <property name="smile.src" value="${smile.root}/src"/> | |||||
| <property name="smile.classes" value="${smile.root}/classes"/> | |||||
| <property name="smile.jar.dir" value="${smile.root}/jars"/> | |||||
| <property name="smile.jar" value="${smile.jar.dir}/smile.jar"/> | |||||
| <property name="smile.pkg" value= "org.apache.tools.ant.test.smile"/> | |||||
| <property name="smile.pkg.dir" value="${smile.src}/org/apache/tools/ant/test/smile"/> | |||||
| <property name="smile.main-class" value="${smile.pkg}.Smile"/> | |||||
| <mkdir dir="${smile.pkg.dir}"/> | |||||
| <echo file="${smile.pkg.dir}/Smile.java"> | |||||
| package ${smile.pkg}; | |||||
| import java.util.logging.Logger; | |||||
| import ${hello.pkg}.HelloWorld; | |||||
| public class Smile { | |||||
| public void run() { | |||||
| Logger logger = Logger.getLogger(Smile.class.getName()); | |||||
| logger.info("\u263a\u263b\u263a\u263b"); | |||||
| } | |||||
| public static void main(String[] args) { | |||||
| new Smile().run(); | |||||
| new HelloWorld().run(); | |||||
| } | |||||
| } | |||||
| </echo> | |||||
| <echo file="${smile.src}/module-info.java"> | |||||
| module ${smile.pkg} { | |||||
| exports ${smile.pkg}; | |||||
| requires java.logging; | |||||
| requires ${hello.pkg}; | |||||
| } | |||||
| </echo> | |||||
| <mkdir dir="${smile.classes}"/> | |||||
| <javac srcdir="${smile.src}" destdir="${smile.classes}" | |||||
| includeAntRuntime="false" | |||||
| modulepath="${hello.jar}"/> | |||||
| <mkdir dir="${smile.jar.dir}"/> | |||||
| <jar destfile="${smile.jar}" basedir="${smile.classes}"/> | |||||
| </target> | |||||
| <!-- Creates additional modular jar, with only Java SE dependencies. --> | |||||
| <target name="-foobar" depends="-smile"> | |||||
| <property name="foobar.root" value="${input}/foobar"/> | |||||
| <property name="foobar.src" value="${foobar.root}/src"/> | |||||
| <property name="foobar.classes" value="${foobar.root}/classes"/> | |||||
| <property name="foobar.jar.dir" value="${foobar.root}/jars"/> | |||||
| <property name="foobar.jar" value="${foobar.jar.dir}/foobar.jar"/> | |||||
| <property name="foobar.pkg" value= "org.apache.tools.ant.test.foobar"/> | |||||
| <property name="foobar.pkg.dir" value="${foobar.src}/org/apache/tools/ant/test/foobar"/> | |||||
| <property name="foobar.main-class" value="${foobar.pkg}.FooBar"/> | |||||
| <mkdir dir="${foobar.pkg.dir}"/> | |||||
| <echo file="${foobar.pkg.dir}/FooBar.java"> | |||||
| package ${foobar.pkg}; | |||||
| import ${hello.main-class}; | |||||
| import ${smile.main-class}; | |||||
| public class FooBar { | |||||
| public void run() { | |||||
| new HelloWorld().run(); | |||||
| new Smile().run(); | |||||
| } | |||||
| public static void main(String[] args) { | |||||
| new FooBar().run(); | |||||
| } | |||||
| } | |||||
| </echo> | |||||
| <echo file="${foobar.src}/module-info.java"> | |||||
| module ${foobar.pkg} { | |||||
| exports ${foobar.pkg}; | |||||
| requires java.logging; | |||||
| requires ${hello.pkg}; | |||||
| requires ${smile.pkg}; | |||||
| } | |||||
| </echo> | |||||
| <mkdir dir="${foobar.classes}"/> | |||||
| <javac srcdir="${foobar.src}" destdir="${foobar.classes}" | |||||
| includeAntRuntime="false" modulepath="${hello.jar};${smile.jar}"/> | |||||
| <mkdir dir="${foobar.jar.dir}"/> | |||||
| <jar destfile="${foobar.jar}" basedir="${foobar.classes}"/> | |||||
| </target> | |||||
| <target name="destAndClasspathNoJmod" depends="-hello"> | |||||
| <jmod destfile="${jmod}" classpath="${hello.jar}"/> | |||||
| </target> | |||||
| <target name="destAndClasspathOlderThanJmod" depends="-hello"> | |||||
| <property name="dateformat" value="yyyy-MM-dd HH:mm:ss.SSS"/> | |||||
| <tstamp> | |||||
| <format property="future" pattern="${dateformat}" offset="1" unit="hour"/> | |||||
| </tstamp> | |||||
| <touch file="${jmod}" datetime="${future}" pattern="${dateformat}"/> | |||||
| <jmod destfile="${jmod}" classpath="${hello.jar}"/> | |||||
| </target> | |||||
| <target name="noDestFile"> | |||||
| <jmod classpath="."/> | |||||
| </target> | |||||
| <target name="noClasspath"> | |||||
| <jmod destfile="${jmod}"/> | |||||
| </target> | |||||
| <target name="emptyClasspath"> | |||||
| <jmod destfile="${jmod}" classpath=""/> | |||||
| </target> | |||||
| <target name="nonexistentClasspath"> | |||||
| <jmod destfile="${jmod}" classpath="dummy:dummy2"/> | |||||
| </target> | |||||
| <target name="classpathref" depends="-hello"> | |||||
| <path id="classpathref.testpath"> | |||||
| <pathelement location="${hello.jar}"/> | |||||
| </path> | |||||
| <jmod destfile="${jmod}" classpathref="classpathref.testpath"/> | |||||
| </target> | |||||
| <target name="classpath-nested" depends="-hello"> | |||||
| <jmod destfile="${jmod}"> | |||||
| <classpath> | |||||
| <pathelement location="${hello.jar}"/> | |||||
| </classpath> | |||||
| </jmod> | |||||
| </target> | |||||
| <target name="classpath-both" depends="-smile"> | |||||
| <jmod destfile="${jmod}" classpath="${hello.jar}"> | |||||
| <classpath> | |||||
| <pathelement location="${smile.classes}"/> | |||||
| </classpath> | |||||
| </jmod> | |||||
| </target> | |||||
| <!-- modulepath targets --> | |||||
| <target name="modulepath" depends="-smile"> | |||||
| <jmod destfile="${jmod}" classpath="${smile.jar}" | |||||
| modulepath="${hello.jar.dir}"/> | |||||
| </target> | |||||
| <target name="modulepathref" depends="-smile"> | |||||
| <path id="modulepathref.testpath"> | |||||
| <pathelement location="${hello.jar.dir}"/> | |||||
| </path> | |||||
| <jmod destfile="${jmod}" classpath="${smile.jar}" | |||||
| modulepathref="modulepathref.testpath"/> | |||||
| </target> | |||||
| <target name="modulepath-nested" depends="-smile"> | |||||
| <jmod destfile="${jmod}" classpath="${smile.jar}"> | |||||
| <modulepath> | |||||
| <pathelement location="${hello.jar.dir}"/> | |||||
| </modulepath> | |||||
| </jmod> | |||||
| </target> | |||||
| <target name="modulepath-both" depends="-smile,-foobar"> | |||||
| <jmod destfile="${jmod}" classpath="${foobar.jar}" | |||||
| modulepath="${hello.jar.dir}"> | |||||
| <modulepath> | |||||
| <pathelement location="${smile.jar.dir}"/> | |||||
| </modulepath> | |||||
| </jmod> | |||||
| </target> | |||||
| <target name="modulepathnondir" depends="-smile"> | |||||
| <jmod destfile="${jmod}" classpath="${smile.jar}" | |||||
| modulepath="${hello.jar}"/> | |||||
| </target> | |||||
| <!-- commandpath targets --> | |||||
| <target name="commandpath" depends="-hello"> | |||||
| <property name="commands" value="${output}/commands"/> | |||||
| <mkdir dir="${commands}"/> | |||||
| <property name="command1" value="${commands}/command1"/> | |||||
| <echo file="${command1}"> | |||||
| #!/bin/bash | |||||
| `dirname "$0"`/java -m ${hello.pkg}/${hello.pkg}.HelloWorld | |||||
| </echo> | |||||
| <setpermissions mode="777" nonPosixMode="tryDosOrPass"> | |||||
| <file file="${command1}"/> | |||||
| </setpermissions> | |||||
| <jmod destfile="${jmod}" classpath="${hello.jar}" | |||||
| commandpath="${commands}"/> | |||||
| </target> | |||||
| <target name="commandpathref" depends="-hello"> | |||||
| <property name="commands" value="${output}/commands"/> | |||||
| <mkdir dir="${commands}"/> | |||||
| <property name="command2" value="${commands}/command2"/> | |||||
| <echo file="${command2}"> | |||||
| #!/bin/bash | |||||
| `dirname "$0"`/java -m ${hello.pkg}/${hello.pkg}.HelloWorld | |||||
| </echo> | |||||
| <setpermissions mode="777" nonPosixMode="tryDosOrPass"> | |||||
| <file file="${command2}"/> | |||||
| </setpermissions> | |||||
| <path id="commandpathref.testpath"> | |||||
| <pathelement location="${commands}"/> | |||||
| </path> | |||||
| <jmod destfile="${jmod}" classpath="${hello.jar}" | |||||
| commandpathref="commandpathref.testpath"/> | |||||
| </target> | |||||
| <target name="commandpath-nested" depends="-hello"> | |||||
| <property name="commands" value="${output}/commands"/> | |||||
| <mkdir dir="${commands}"/> | |||||
| <property name="command3" value="${commands}/command3"/> | |||||
| <echo file="${command3}"> | |||||
| #!/bin/bash | |||||
| `dirname "$0"`/java -m ${hello.pkg}/${hello.pkg}.HelloWorld | |||||
| </echo> | |||||
| <setpermissions mode="777" nonPosixMode="tryDosOrPass"> | |||||
| <file file="${command3}"/> | |||||
| </setpermissions> | |||||
| <jmod destfile="${jmod}" classpath="${hello.jar}"> | |||||
| <commandpath> | |||||
| <pathelement location="${commands}"/> | |||||
| </commandpath> | |||||
| </jmod> | |||||
| </target> | |||||
| <target name="commandpath-both" depends="-hello"> | |||||
| <property name="commands1" value="${output}/commands1"/> | |||||
| <property name="commands2" value="${output}/commands2"/> | |||||
| <mkdir dir="${commands1}"/> | |||||
| <mkdir dir="${commands2}"/> | |||||
| <property name="command4" value="${commands1}/command4"/> | |||||
| <echo file="${command4}"> | |||||
| #!/bin/bash | |||||
| `dirname "$0"`/java -m ${hello.pkg}/${hello.pkg}.HelloWorld | |||||
| </echo> | |||||
| <setpermissions mode="777" nonPosixMode="tryDosOrPass"> | |||||
| <file file="${command4}"/> | |||||
| </setpermissions> | |||||
| <property name="command5" value="${commands2}/command5"/> | |||||
| <echo file="${command5}"> | |||||
| #!/bin/bash | |||||
| `dirname "$0"`/java -m ${hello.pkg}/${hello.pkg}.HelloWorld | |||||
| </echo> | |||||
| <setpermissions mode="777" nonPosixMode="tryDosOrPass"> | |||||
| <file file="${command5}"/> | |||||
| </setpermissions> | |||||
| <jmod destfile="${jmod}" classpath="${hello.jar}" | |||||
| commandpath="${commands1}"> | |||||
| <commandpath> | |||||
| <pathelement location="${commands2}"/> | |||||
| </commandpath> | |||||
| </jmod> | |||||
| </target> | |||||
| <!-- headerpath targets --> | |||||
| <target name="headerpath" depends="-hello"> | |||||
| <property name="headers" value="${output}/headers"/> | |||||
| <mkdir dir="${headers}"/> | |||||
| <property name="header1" value="${headers}/header1.h"/> | |||||
| <echo file="${header1}"> | |||||
| typedef int index_t; | |||||
| </echo> | |||||
| <jmod destfile="${jmod}" classpath="${hello.jar}" | |||||
| headerpath="${headers}"/> | |||||
| </target> | |||||
| <target name="headerpathref" depends="-hello"> | |||||
| <property name="headers" value="${output}/headers"/> | |||||
| <mkdir dir="${headers}"/> | |||||
| <property name="header2" value="${headers}/header2.h"/> | |||||
| <echo file="${header2}"> | |||||
| typedef char * string_t; | |||||
| </echo> | |||||
| <path id="headerpathref.testpath"> | |||||
| <pathelement location="${headers}"/> | |||||
| </path> | |||||
| <jmod destfile="${jmod}" classpath="${hello.jar}" | |||||
| headerpathref="headerpathref.testpath"/> | |||||
| </target> | |||||
| <target name="headerpath-nested" depends="-hello"> | |||||
| <property name="headers" value="${output}/headers"/> | |||||
| <mkdir dir="${headers}"/> | |||||
| <property name="header3" value="${headers}/header3.h"/> | |||||
| <echo file="${header3}"> | |||||
| typedef char * string_t; | |||||
| </echo> | |||||
| <jmod destfile="${jmod}" classpath="${hello.jar}"> | |||||
| <headerpath> | |||||
| <pathelement location="${headers}"/> | |||||
| </headerpath> | |||||
| </jmod> | |||||
| </target> | |||||
| <target name="headerpath-both" depends="-hello"> | |||||
| <property name="headers4" value="${output}/headers4"/> | |||||
| <property name="headers5" value="${output}/headers5"/> | |||||
| <mkdir dir="${headers4}"/> | |||||
| <mkdir dir="${headers5}"/> | |||||
| <property name="header4" value="${headers4}/header4.h"/> | |||||
| <property name="header5" value="${headers5}/header5.h"/> | |||||
| <echo file="${header4}"> | |||||
| typedef int index_t; | |||||
| </echo> | |||||
| <echo file="${header5}"> | |||||
| typedef char * string_t; | |||||
| </echo> | |||||
| <jmod destfile="${jmod}" classpath="${hello.jar}" headerpath="${headers4}"> | |||||
| <headerpath> | |||||
| <pathelement location="${headers5}"/> | |||||
| </headerpath> | |||||
| </jmod> | |||||
| </target> | |||||
| <!-- configpath targets --> | |||||
| <target name="configpath" depends="-hello"> | |||||
| <property name="config" value="${output}/config"/> | |||||
| <mkdir dir="${config}"/> | |||||
| <property name="config1" value="${config}/config1.properties"/> | |||||
| <echo file="${config1}"> | |||||
| timeout=3600 | |||||
| </echo> | |||||
| <jmod destfile="${jmod}" classpath="${hello.jar}" configpath="${config}"/> | |||||
| </target> | |||||
| <target name="configpathref" depends="-hello"> | |||||
| <property name="config" value="${output}/config"/> | |||||
| <mkdir dir="${config}"/> | |||||
| <property name="config2" value="${config}/config2.properties"/> | |||||
| <echo file="${config2}"> | |||||
| timeout=7200 | |||||
| </echo> | |||||
| <path id="configpathref.testpath"> | |||||
| <pathelement location="${config}"/> | |||||
| </path> | |||||
| <jmod destfile="${jmod}" classpath="${hello.jar}" | |||||
| configpathref="configpathref.testpath"/> | |||||
| </target> | |||||
| <target name="configpath-nested" depends="-hello"> | |||||
| <property name="config" value="${output}/config"/> | |||||
| <mkdir dir="${config}"/> | |||||
| <property name="config3" value="${config}/config3.properties"/> | |||||
| <echo file="${config3}"> | |||||
| timeout=7200 | |||||
| </echo> | |||||
| <jmod destfile="${jmod}" classpath="${hello.jar}"> | |||||
| <configpath> | |||||
| <pathelement location="${config}"/> | |||||
| </configpath> | |||||
| </jmod> | |||||
| </target> | |||||
| <target name="configpath-both" depends="-hello"> | |||||
| <property name="config4" value="${output}/config4"/> | |||||
| <property name="config5" value="${output}/config5"/> | |||||
| <mkdir dir="${config4}"/> | |||||
| <mkdir dir="${config5}"/> | |||||
| <property name="configfile4" value="${config4}/config4.properties"/> | |||||
| <property name="configfile5" value="${config5}/config5.properties"/> | |||||
| <echo file="${configfile4}"> | |||||
| timeout=3600 | |||||
| </echo> | |||||
| <echo file="${configfile5}"> | |||||
| timeout=7200 | |||||
| </echo> | |||||
| <jmod destfile="${jmod}" classpath="${hello.jar}" configpath="${config4}"> | |||||
| <configpath> | |||||
| <pathelement location="${config5}"/> | |||||
| </configpath> | |||||
| </jmod> | |||||
| </target> | |||||
| <!-- legalpath targets --> | |||||
| <target name="legalpath" depends="-hello"> | |||||
| <property name="legal" value="${output}/legal"/> | |||||
| <mkdir dir="${legal}"/> | |||||
| <property name="legal1" value="${legal}/legal1.txt"/> | |||||
| <echo file="${legal1}"> | |||||
| 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 | |||||
| http://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. | |||||
| </echo> | |||||
| <jmod destfile="${jmod}" classpath="${hello.jar}" legalpath="${legal}"/> | |||||
| </target> | |||||
| <target name="legalpathref" depends="-hello"> | |||||
| <property name="legal" value="${output}/legal"/> | |||||
| <mkdir dir="${legal}"/> | |||||
| <property name="legal2" value="${legal}/legal2.txt"/> | |||||
| <echo file="${legal2}"> | |||||
| 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 | |||||
| http://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. | |||||
| </echo> | |||||
| <path id="legalpathref.testpath"> | |||||
| <pathelement location="${legal}"/> | |||||
| </path> | |||||
| <jmod destfile="${jmod}" classpath="${hello.jar}" | |||||
| legalpathref="legalpathref.testpath"/> | |||||
| </target> | |||||
| <target name="legalpath-nested" depends="-hello"> | |||||
| <property name="legal" value="${output}/legal"/> | |||||
| <mkdir dir="${legal}"/> | |||||
| <property name="legal3" value="${legal}/legal3.txt"/> | |||||
| <echo file="${legal3}"> | |||||
| 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 | |||||
| http://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. | |||||
| </echo> | |||||
| <jmod destfile="${jmod}" classpath="${hello.jar}"> | |||||
| <legalpath> | |||||
| <pathelement location="${legal}"/> | |||||
| </legalpath> | |||||
| </jmod> | |||||
| </target> | |||||
| <target name="legalpath-both" depends="-hello"> | |||||
| <property name="legal4" value="${output}/legal4"/> | |||||
| <property name="legal5" value="${output}/legal5"/> | |||||
| <mkdir dir="${legal4}"/> | |||||
| <mkdir dir="${legal5}"/> | |||||
| <property name="legalfile4" value="${legal4}/legal4.txt"/> | |||||
| <property name="legalfile5" value="${legal5}/legal5.txt"/> | |||||
| <echo file="${legalfile4}"> | |||||
| 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 | |||||
| http://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. | |||||
| </echo> | |||||
| <copy file="${legalfile4}" tofile="${legalfile5}"/> | |||||
| <jmod destfile="${jmod}" classpath="${hello.jar}" legalpath="${legal4}"> | |||||
| <legalpath> | |||||
| <pathelement location="${legal5}"/> | |||||
| </legalpath> | |||||
| </jmod> | |||||
| </target> | |||||
| <!-- manpath targets --> | |||||
| <target name="manpath" depends="-hello"> | |||||
| <property name="manpages" value="${output}/manpages"/> | |||||
| <mkdir dir="${manpages}"/> | |||||
| <property name="man1" value="${manpages}/man1.1"/> | |||||
| <echo file="${man1}"><!-- | |||||
| --><![CDATA[.TH TRUE "1" "February 2017" "GNU coreutils 8.26" "User Commands" | |||||
| .SH NAME | |||||
| true \- do nothing, successfully | |||||
| .SH SYNOPSIS | |||||
| .B true | |||||
| [\fI\,ignored command line arguments\/\fR] | |||||
| .br | |||||
| .B true | |||||
| \fI\,OPTION\/\fR | |||||
| .SH DESCRIPTION | |||||
| .\" Add any additional description here | |||||
| .PP | |||||
| Exit with a status code indicating success. | |||||
| .TP | |||||
| \fB\-\-help\fR | |||||
| display this help and exit | |||||
| .TP | |||||
| \fB\-\-version\fR | |||||
| output version information and exit | |||||
| .PP | |||||
| NOTE: your shell may have its own version of true, which usually supersedes | |||||
| the version described here. Please refer to your shell's documentation | |||||
| for details about the options it supports. | |||||
| .SH AUTHOR | |||||
| Written by Jim Meyering. | |||||
| .SH "REPORTING BUGS" | |||||
| GNU coreutils online help: <http://www.gnu.org/software/coreutils/> | |||||
| .br | |||||
| Report true translation bugs to <http://translationproject.org/team/> | |||||
| .SH COPYRIGHT | |||||
| Copyright \(co 2016 Free Software Foundation, Inc. | |||||
| License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>. | |||||
| .br | |||||
| This is free software: you are free to change and redistribute it. | |||||
| There is NO WARRANTY, to the extent permitted by law. | |||||
| .SH "SEE ALSO" | |||||
| Full documentation at: <http://www.gnu.org/software/coreutils/true> | |||||
| ]]><!-- | |||||
| --></echo> | |||||
| <jmod destfile="${jmod}" classpath="${hello.jar}" manpath="${manpages}"/> | |||||
| </target> | |||||
| <target name="manpathref" depends="-hello"> | |||||
| <property name="manpages" value="${output}/manpages"/> | |||||
| <mkdir dir="${manpages}"/> | |||||
| <property name="man2" value="${manpages}/man2.1"/> | |||||
| <echo file="${man2}"><!-- | |||||
| --><![CDATA[.TH FALSE "1" "February 2017" "GNU coreutils 8.26" "User Commands" | |||||
| .SH NAME | |||||
| false \- do nothing, unsuccessfully | |||||
| .SH SYNOPSIS | |||||
| .B false | |||||
| [\fI\,ignored command line arguments\/\fR] | |||||
| .br | |||||
| .B false | |||||
| \fI\,OPTION\/\fR | |||||
| .SH DESCRIPTION | |||||
| .\" Add any additional description here | |||||
| .PP | |||||
| Exit with a status code indicating failure. | |||||
| .TP | |||||
| \fB\-\-help\fR | |||||
| display this help and exit | |||||
| .TP | |||||
| \fB\-\-version\fR | |||||
| output version information and exit | |||||
| .PP | |||||
| NOTE: your shell may have its own version of false, which usually supersedes | |||||
| the version described here. Please refer to your shell's documentation | |||||
| for details about the options it supports. | |||||
| .SH AUTHOR | |||||
| Written by Jim Meyering. | |||||
| .SH "REPORTING BUGS" | |||||
| GNU coreutils online help: <http://www.gnu.org/software/coreutils/> | |||||
| .br | |||||
| Report false translation bugs to <http://translationproject.org/team/> | |||||
| .SH COPYRIGHT | |||||
| Copyright \(co 2016 Free Software Foundation, Inc. | |||||
| License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>. | |||||
| .br | |||||
| This is free software: you are free to change and redistribute it. | |||||
| There is NO WARRANTY, to the extent permitted by law. | |||||
| .SH "SEE ALSO" | |||||
| Full documentation at: <http://www.gnu.org/software/coreutils/false> | |||||
| ]]><!-- | |||||
| --></echo> | |||||
| <path id="manpathref.testpath"> | |||||
| <pathelement location="${manpages}"/> | |||||
| </path> | |||||
| <jmod destfile="${jmod}" classpath="${hello.jar}" | |||||
| manpathref="manpathref.testpath"/> | |||||
| </target> | |||||
| <target name="manpath-nested" depends="-hello"> | |||||
| <property name="manpages" value="${output}/manpages"/> | |||||
| <mkdir dir="${manpages}"/> | |||||
| <property name="man3" value="${manpages}/man3.1"/> | |||||
| <echo file="${man3}"><!-- | |||||
| --><![CDATA[.TH FALSE "1" "February 2017" "GNU coreutils 8.26" "User Commands" | |||||
| .SH NAME | |||||
| false \- do nothing, unsuccessfully | |||||
| .SH SYNOPSIS | |||||
| .B false | |||||
| [\fI\,ignored command line arguments\/\fR] | |||||
| .br | |||||
| .B false | |||||
| \fI\,OPTION\/\fR | |||||
| .SH DESCRIPTION | |||||
| .\" Add any additional description here | |||||
| .PP | |||||
| Exit with a status code indicating failure. | |||||
| .TP | |||||
| \fB\-\-help\fR | |||||
| display this help and exit | |||||
| .TP | |||||
| \fB\-\-version\fR | |||||
| output version information and exit | |||||
| .PP | |||||
| NOTE: your shell may have its own version of false, which usually supersedes | |||||
| the version described here. Please refer to your shell's documentation | |||||
| for details about the options it supports. | |||||
| .SH AUTHOR | |||||
| Written by Jim Meyering. | |||||
| .SH "REPORTING BUGS" | |||||
| GNU coreutils online help: <http://www.gnu.org/software/coreutils/> | |||||
| .br | |||||
| Report false translation bugs to <http://translationproject.org/team/> | |||||
| .SH COPYRIGHT | |||||
| Copyright \(co 2016 Free Software Foundation, Inc. | |||||
| License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>. | |||||
| .br | |||||
| This is free software: you are free to change and redistribute it. | |||||
| There is NO WARRANTY, to the extent permitted by law. | |||||
| .SH "SEE ALSO" | |||||
| Full documentation at: <http://www.gnu.org/software/coreutils/false> | |||||
| ]]><!-- | |||||
| --></echo> | |||||
| <jmod destfile="${jmod}" classpath="${hello.jar}"> | |||||
| <manpath> | |||||
| <pathelement location="${manpages}"/> | |||||
| </manpath> | |||||
| </jmod> | |||||
| </target> | |||||
| <target name="manpath-both" depends="-hello"> | |||||
| <property name="manpages4" value="${output}/manpages4"/> | |||||
| <property name="manpages5" value="${output}/manpages5"/> | |||||
| <mkdir dir="${manpages4}"/> | |||||
| <mkdir dir="${manpages5}"/> | |||||
| <property name="man4" value="${manpages4}/man4.1"/> | |||||
| <property name="man5" value="${manpages5}/man5.1"/> | |||||
| <echo file="${man4}"><!-- | |||||
| --><![CDATA[.TH TRUE "1" "February 2017" "GNU coreutils 8.26" "User Commands" | |||||
| .SH NAME | |||||
| true \- do nothing, successfully | |||||
| .SH SYNOPSIS | |||||
| .B true | |||||
| [\fI\,ignored command line arguments\/\fR] | |||||
| .br | |||||
| .B true | |||||
| \fI\,OPTION\/\fR | |||||
| .SH DESCRIPTION | |||||
| .\" Add any additional description here | |||||
| .PP | |||||
| Exit with a status code indicating success. | |||||
| .TP | |||||
| \fB\-\-help\fR | |||||
| display this help and exit | |||||
| .TP | |||||
| \fB\-\-version\fR | |||||
| output version information and exit | |||||
| .PP | |||||
| NOTE: your shell may have its own version of true, which usually supersedes | |||||
| the version described here. Please refer to your shell's documentation | |||||
| for details about the options it supports. | |||||
| .SH AUTHOR | |||||
| Written by Jim Meyering. | |||||
| .SH "REPORTING BUGS" | |||||
| GNU coreutils online help: <http://www.gnu.org/software/coreutils/> | |||||
| .br | |||||
| Report true translation bugs to <http://translationproject.org/team/> | |||||
| .SH COPYRIGHT | |||||
| Copyright \(co 2016 Free Software Foundation, Inc. | |||||
| License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>. | |||||
| .br | |||||
| This is free software: you are free to change and redistribute it. | |||||
| There is NO WARRANTY, to the extent permitted by law. | |||||
| .SH "SEE ALSO" | |||||
| Full documentation at: <http://www.gnu.org/software/coreutils/true> | |||||
| ]]><!-- | |||||
| --></echo> | |||||
| <echo file="${man5}"><!-- | |||||
| --><![CDATA[.TH FALSE "1" "February 2017" "GNU coreutils 8.26" "User Commands" | |||||
| .SH NAME | |||||
| false \- do nothing, unsuccessfully | |||||
| .SH SYNOPSIS | |||||
| .B false | |||||
| [\fI\,ignored command line arguments\/\fR] | |||||
| .br | |||||
| .B false | |||||
| \fI\,OPTION\/\fR | |||||
| .SH DESCRIPTION | |||||
| .\" Add any additional description here | |||||
| .PP | |||||
| Exit with a status code indicating failure. | |||||
| .TP | |||||
| \fB\-\-help\fR | |||||
| display this help and exit | |||||
| .TP | |||||
| \fB\-\-version\fR | |||||
| output version information and exit | |||||
| .PP | |||||
| NOTE: your shell may have its own version of false, which usually supersedes | |||||
| the version described here. Please refer to your shell's documentation | |||||
| for details about the options it supports. | |||||
| .SH AUTHOR | |||||
| Written by Jim Meyering. | |||||
| .SH "REPORTING BUGS" | |||||
| GNU coreutils online help: <http://www.gnu.org/software/coreutils/> | |||||
| .br | |||||
| Report false translation bugs to <http://translationproject.org/team/> | |||||
| .SH COPYRIGHT | |||||
| Copyright \(co 2016 Free Software Foundation, Inc. | |||||
| License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>. | |||||
| .br | |||||
| This is free software: you are free to change and redistribute it. | |||||
| There is NO WARRANTY, to the extent permitted by law. | |||||
| .SH "SEE ALSO" | |||||
| Full documentation at: <http://www.gnu.org/software/coreutils/false> | |||||
| ]]><!-- | |||||
| --></echo> | |||||
| <jmod destfile="${jmod}" classpath="${hello.jar}" manpath="${manpages4}"> | |||||
| <manpath> | |||||
| <pathelement location="${manpages5}"/> | |||||
| </manpath> | |||||
| </jmod> | |||||
| </target> | |||||
| <!-- nativelibpath targets --> | |||||
| <target name="nativelibpath" depends="-hello"> | |||||
| <property name="nativelib" location="${java.home}/lib;${java.home}/bin"/> | |||||
| <jmod destfile="${jmod}" classpath="${hello.jar}" | |||||
| nativelibpath="${nativelib}"/> | |||||
| </target> | |||||
| <target name="nativelibpathref" depends="-hello"> | |||||
| <path id="nativelibpathref.testpath"> | |||||
| <pathelement location="${java.home}/lib"/> | |||||
| <pathelement location="${java.home}/bin"/> | |||||
| </path> | |||||
| <jmod destfile="${jmod}" classpath="${hello.jar}" | |||||
| nativelibpathref="nativelibpathref.testpath"/> | |||||
| </target> | |||||
| <target name="nativelibpath-nested" depends="-hello"> | |||||
| <jmod destfile="${jmod}" classpath="${hello.jar}"> | |||||
| <nativelibpath> | |||||
| <pathelement location="${java.home}/lib"/> | |||||
| <pathelement location="${java.home}/bin"/> | |||||
| </nativelibpath> | |||||
| </jmod> | |||||
| </target> | |||||
| <target name="nativelibpath-both" depends="-hello"> | |||||
| <jmod destfile="${jmod}" classpath="${hello.jar}" | |||||
| nativelibpath="${java.home}/lib;${java.home}/bin"> | |||||
| <nativelibpath> | |||||
| <dirset dir="${java.home}"> | |||||
| <include name="lib/server"/> | |||||
| <include name="bin/server"/> | |||||
| </dirset> | |||||
| </nativelibpath> | |||||
| </jmod> | |||||
| </target> | |||||
| <!-- non-path targets --> | |||||
| <target name="version" depends="-hello"> | |||||
| <jmod destfile="${jmod}" classpath="${hello.jar}" version="${version}"/> | |||||
| </target> | |||||
| <target name="version-nested" depends="-hello"> | |||||
| <jmod destfile="${jmod}" classpath="${hello.jar}"> | |||||
| <version number="1.0.1" build="99"/> | |||||
| </jmod> | |||||
| </target> | |||||
| <target name="version-nested-number" depends="-hello"> | |||||
| <jmod destfile="${jmod}" classpath="${hello.jar}"> | |||||
| <version number="1.0.1"/> | |||||
| </jmod> | |||||
| </target> | |||||
| <target name="version-nested-no-number" depends="-hello"> | |||||
| <jmod destfile="${jmod}" classpath="${hello.jar}"> | |||||
| <version build="99"/> | |||||
| </jmod> | |||||
| </target> | |||||
| <target name="version-nested-invalid-number" depends="-hello"> | |||||
| <jmod destfile="${jmod}" classpath="${hello.jar}"> | |||||
| <version number="1-0-1" build="99"/> | |||||
| </jmod> | |||||
| </target> | |||||
| <target name="version-nested-invalid-prerelease" depends="-hello"> | |||||
| <jmod destfile="${jmod}" classpath="${hello.jar}"> | |||||
| <version number="1.0.1" build="99" prerelease="unit+testing"/> | |||||
| </jmod> | |||||
| </target> | |||||
| <target name="version-both" depends="-hello"> | |||||
| <jmod destfile="${jmod}" classpath="${hello.jar}" version="${version}"> | |||||
| <version number="1.0.1" build="99"/> | |||||
| </jmod> | |||||
| </target> | |||||
| <target name="mainclass" depends="-hello"> | |||||
| <jmod destfile="${jmod}" classpath="${hello.jar}" | |||||
| mainclass="${hello.main-class}"/> | |||||
| </target> | |||||
| <target name="platform" depends="-smile"> | |||||
| <property name="target-platform" value="windows-amd64"/> | |||||
| <jmod destfile="${jmod}" classpath="${hello.jar}" | |||||
| platform="${target-platform}"/> | |||||
| </target> | |||||
| <target name="hashing" depends="-smile"> | |||||
| <jmod destfile="${jmod}" classpath="${hello.jar}" | |||||
| modulepath="${smile.jar.dir}" | |||||
| hashModulesPattern=".*smile.*"/> | |||||
| </target> | |||||
| </project> | |||||
| @@ -66,6 +66,8 @@ jar=org.apache.tools.ant.taskdefs.Jar | |||||
| java=org.apache.tools.ant.taskdefs.Java | java=org.apache.tools.ant.taskdefs.Java | ||||
| javac=org.apache.tools.ant.taskdefs.Javac | javac=org.apache.tools.ant.taskdefs.Javac | ||||
| javadoc=org.apache.tools.ant.taskdefs.Javadoc | javadoc=org.apache.tools.ant.taskdefs.Javadoc | ||||
| jmod=org.apache.tools.ant.taskdefs.modules.Jmod | |||||
| link=org.apache.tools.ant.taskdefs.modules.Link | |||||
| length=org.apache.tools.ant.taskdefs.Length | length=org.apache.tools.ant.taskdefs.Length | ||||
| loadfile=org.apache.tools.ant.taskdefs.LoadFile | loadfile=org.apache.tools.ant.taskdefs.LoadFile | ||||
| loadproperties=org.apache.tools.ant.taskdefs.LoadProperties | loadproperties=org.apache.tools.ant.taskdefs.LoadProperties | ||||
| @@ -0,0 +1,23 @@ | |||||
| /* | |||||
| * 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 | |||||
| * | |||||
| * http://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. | |||||
| * | |||||
| */ | |||||
| /** | |||||
| * Tasks for dealing with Java modules, which are supported starting with | |||||
| * Java 9. | |||||
| */ | |||||
| package org.apache.tools.ant.taskdefs.modules; | |||||
| @@ -25,8 +25,10 @@ import org.apache.tools.ant.taskdefs.MatchingTask; | |||||
| import org.apache.tools.ant.types.Path; | import org.apache.tools.ant.types.Path; | ||||
| /** | /** | ||||
| * This class defines objects that can link together various jar and | |||||
| * zip files. | |||||
| * This task defines objects that can link together various jar and | |||||
| * zip files. It is not related to the {@code jlink} tool present in | |||||
| * Java 9 and later; for that, see | |||||
| * {@link org.apache.tools.ant.taskdefs.modules.Link}. | |||||
| * | * | ||||
| * <p>It is basically a wrapper for the jlink code written originally | * <p>It is basically a wrapper for the jlink code written originally | ||||
| * by <a href="mailto:beard@netscape.com">Patrick Beard</a>. The | * by <a href="mailto:beard@netscape.com">Patrick Beard</a>. The | ||||
| @@ -0,0 +1,147 @@ | |||||
| /* | |||||
| * 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 | |||||
| * | |||||
| * http://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. | |||||
| * | |||||
| */ | |||||
| package org.apache.tools.ant.types; | |||||
| import java.util.Objects; | |||||
| /** | |||||
| * Element describing the parts of a Java | |||||
| * <a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/module/ModuleDescriptor.Version.html">module version</a>. | |||||
| * The version number is required; all other parts are optional. | |||||
| */ | |||||
| public class ModuleVersion { | |||||
| /** Module version's required <em>version number</em>. */ | |||||
| private String number; | |||||
| /** Module version's optional <em>pre-release version</em>. */ | |||||
| private String preRelease; | |||||
| /** Module version's optional <em>build version</em>. */ | |||||
| private String build; | |||||
| /** | |||||
| * Returns this element's version number. | |||||
| * | |||||
| * @return version number | |||||
| */ | |||||
| public String getNumber() { | |||||
| return number; | |||||
| } | |||||
| /** | |||||
| * Sets this element's required version number. This cannot contain | |||||
| * an ASCII hyphen ({@code -}) or plus ({@code +}), as those characters | |||||
| * are used as delimiters in a complete module version string. | |||||
| * | |||||
| * @throws NullPointerException if argument is {@code null} | |||||
| * @throws IllegalArgumentException if argument contains {@code '-'} | |||||
| * or {@code '+'} | |||||
| */ | |||||
| public void setNumber(final String number) { | |||||
| Objects.requireNonNull(number, "Version number cannot be null."); | |||||
| if (number.indexOf('-') >= 0 || number.indexOf('+') >= 0) { | |||||
| throw new IllegalArgumentException( | |||||
| "Version number cannot contain '-' or '+'."); | |||||
| } | |||||
| this.number = number; | |||||
| } | |||||
| /** | |||||
| * Returns this element's pre-release version, if set. | |||||
| * | |||||
| * @return pre-release value, or {@code null} | |||||
| */ | |||||
| public String getPreRelease() { | |||||
| return preRelease; | |||||
| } | |||||
| /** | |||||
| * Sets this element's pre-release version. This can be any value | |||||
| * which doesn't contain an ASCII plus ({@code +}). | |||||
| * | |||||
| * @param pre pre-release version, or {@code null} | |||||
| * | |||||
| * @throws IllegalArgumentException if argument contains "{@code +}" | |||||
| */ | |||||
| public void setPreRelease(final String pre) { | |||||
| if (pre != null && pre.indexOf('+') >= 0) { | |||||
| throw new IllegalArgumentException( | |||||
| "Version's pre-release cannot contain '+'."); | |||||
| } | |||||
| this.preRelease = pre; | |||||
| } | |||||
| /** | |||||
| * Returns this element's build version, if set. | |||||
| * | |||||
| * @return build value, or {@code null} | |||||
| */ | |||||
| public String getBuild() { | |||||
| return build; | |||||
| } | |||||
| /** | |||||
| * Sets this element's build version. This can be any value, including | |||||
| * {@code null}. | |||||
| * | |||||
| * @param build build version, or {@code null} | |||||
| */ | |||||
| public void setBuild(final String build) { | |||||
| this.build = build; | |||||
| } | |||||
| /** | |||||
| * Snapshots this element's state and converts it to a string compliant | |||||
| * with {@code ModuleDescriptor.Version}. | |||||
| * | |||||
| * @return Java module version string built from this object's properties | |||||
| * | |||||
| * @throws IllegalStateException if {@linkplain #getNumber() number} | |||||
| * is {@code null} | |||||
| */ | |||||
| public String toModuleVersionString() { | |||||
| if (number == null) { | |||||
| throw new IllegalStateException("Version number cannot be null."); | |||||
| } | |||||
| StringBuilder version = new StringBuilder(number); | |||||
| if (preRelease != null || build != null) { | |||||
| version.append('-').append(Objects.toString(preRelease, "")); | |||||
| } | |||||
| if (build != null) { | |||||
| version.append('+').append(build); | |||||
| } | |||||
| return version.toString(); | |||||
| } | |||||
| /** | |||||
| * Returns a summary of this object's state, suitable for debugging. | |||||
| * | |||||
| * @return string form of this instance | |||||
| */ | |||||
| @Override | |||||
| public String toString() { | |||||
| return getClass().getName() + | |||||
| "[number=" + number + | |||||
| ", preRelease=" + preRelease + | |||||
| ", build=" + build + | |||||
| "]"; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,690 @@ | |||||
| /* | |||||
| * 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 | |||||
| * | |||||
| * http://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. | |||||
| * | |||||
| */ | |||||
| package org.apache.tools.ant.taskdefs.modules; | |||||
| import java.io.BufferedReader; | |||||
| import java.io.StringReader; | |||||
| import java.io.ByteArrayOutputStream; | |||||
| import java.io.PrintStream; | |||||
| import java.io.File; | |||||
| import java.io.IOException; | |||||
| import java.nio.file.Files; | |||||
| import java.time.Instant; | |||||
| import java.time.temporal.ChronoUnit; | |||||
| import java.util.function.Predicate; | |||||
| import java.util.regex.Pattern; | |||||
| import java.util.spi.ToolProvider; | |||||
| import org.junit.Assert; | |||||
| import org.junit.Before; | |||||
| import org.junit.Rule; | |||||
| import org.junit.Test; | |||||
| import org.junit.rules.ExpectedException; | |||||
| import org.apache.tools.ant.BuildException; | |||||
| import org.apache.tools.ant.BuildFileRule; | |||||
| /** | |||||
| * Tests the {@link Jmod} task. | |||||
| */ | |||||
| public class JmodTest { | |||||
| @Rule | |||||
| public final BuildFileRule buildRule = new BuildFileRule(); | |||||
| @Rule | |||||
| public final ExpectedException expected = ExpectedException.none(); | |||||
| @Before | |||||
| public void setUp() { | |||||
| buildRule.configureProject("src/etc/testcases/taskdefs/jmod.xml"); | |||||
| buildRule.executeTarget("setUp"); | |||||
| } | |||||
| @Test | |||||
| public void testDestAndClasspathNoJmod() { | |||||
| buildRule.executeTarget("destAndClasspathNoJmod"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| Assert.assertTrue("Checking that jmod was successfully created.", | |||||
| jmod.exists()); | |||||
| } | |||||
| @Test | |||||
| public void testDestAndNestedClasspath() { | |||||
| buildRule.executeTarget("classpath-nested"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| Assert.assertTrue("Checking that jmod was successfully created.", | |||||
| jmod.exists()); | |||||
| } | |||||
| @Test | |||||
| public void testDestAndClasspathOlderThanJmod() | |||||
| throws IOException { | |||||
| buildRule.executeTarget("destAndClasspathOlderThanJmod"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| File jar = new File(buildRule.getProject().getProperty("hello.jar")); | |||||
| Assert.assertTrue("Checking that newer jmod was not written " | |||||
| + "when source files are older.", | |||||
| Files.getLastModifiedTime(jmod.toPath()).toInstant().isAfter( | |||||
| Instant.now().plus(30, ChronoUnit.MINUTES))); | |||||
| } | |||||
| @Test | |||||
| public void testNoDestFile() { | |||||
| expected.expect(BuildException.class); | |||||
| buildRule.executeTarget("noDestFile"); | |||||
| } | |||||
| @Test | |||||
| public void testNoClasspath() { | |||||
| expected.expect(BuildException.class); | |||||
| buildRule.executeTarget("noClasspath"); | |||||
| } | |||||
| @Test | |||||
| public void testEmptyClasspath() { | |||||
| expected.expect(BuildException.class); | |||||
| buildRule.executeTarget("emptyClasspath"); | |||||
| } | |||||
| @Test | |||||
| public void testClasspathEntirelyNonexistent() { | |||||
| expected.expect(BuildException.class); | |||||
| buildRule.executeTarget("nonexistentClasspath"); | |||||
| } | |||||
| @Test | |||||
| public void testClasspathref() { | |||||
| buildRule.executeTarget("classpathref"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| Assert.assertTrue("Checking that jmod was successfully created.", | |||||
| jmod.exists()); | |||||
| } | |||||
| @Test | |||||
| public void testClasspathAttributeAndChildElement() { | |||||
| buildRule.executeTarget("classpath-both"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| Assert.assertTrue("Checking that jmod was successfully created.", | |||||
| jmod.exists()); | |||||
| } | |||||
| @Test | |||||
| public void testModulepath() { | |||||
| buildRule.executeTarget("modulepath"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| Assert.assertTrue("Checking that jmod was successfully created.", | |||||
| jmod.exists()); | |||||
| } | |||||
| @Test | |||||
| public void testModulepathref() { | |||||
| buildRule.executeTarget("modulepathref"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| Assert.assertTrue("Checking that jmod was successfully created.", | |||||
| jmod.exists()); | |||||
| } | |||||
| @Test | |||||
| public void testModulepathNested() { | |||||
| buildRule.executeTarget("modulepath-nested"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| Assert.assertTrue("Checking that jmod was successfully created.", | |||||
| jmod.exists()); | |||||
| } | |||||
| @Test | |||||
| public void testModulepathNonDir() { | |||||
| expected.expect(BuildException.class); | |||||
| buildRule.executeTarget("modulepathnondir"); | |||||
| } | |||||
| @Test | |||||
| public void testModulepathAttributeAndChildElement() { | |||||
| buildRule.executeTarget("modulepath-both"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| Assert.assertTrue("Checking that jmod was successfully created.", | |||||
| jmod.exists()); | |||||
| } | |||||
| @Test | |||||
| public void testCommandPath() { | |||||
| buildRule.executeTarget("commandpath"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| Assert.assertTrue("Checking that jmod was successfully created.", | |||||
| jmod.exists()); | |||||
| String output = runJmod("list", jmod.toString()); | |||||
| Assert.assertTrue("Checking that jmod contains command.", | |||||
| containsLine(output, l -> l.equals("bin/command1"))); | |||||
| } | |||||
| @Test | |||||
| public void testCommandPathref() { | |||||
| buildRule.executeTarget("commandpathref"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| Assert.assertTrue("Checking that jmod was successfully created.", | |||||
| jmod.exists()); | |||||
| String output = runJmod("list", jmod.toString()); | |||||
| Assert.assertTrue("Checking that jmod contains command.", | |||||
| containsLine(output, l -> l.equals("bin/command2"))); | |||||
| } | |||||
| @Test | |||||
| public void testCommandPathNested() { | |||||
| buildRule.executeTarget("commandpath-nested"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| Assert.assertTrue("Checking that jmod was successfully created.", | |||||
| jmod.exists()); | |||||
| String output = runJmod("list", jmod.toString()); | |||||
| Assert.assertTrue("Checking that jmod contains command.", | |||||
| containsLine(output, l -> l.equals("bin/command3"))); | |||||
| } | |||||
| @Test | |||||
| public void testCommandPathAttributeAndChildElement() { | |||||
| buildRule.executeTarget("commandpath-both"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| Assert.assertTrue("Checking that jmod was successfully created.", | |||||
| jmod.exists()); | |||||
| String output = runJmod("list", jmod.toString()); | |||||
| Assert.assertTrue("Checking that jmod contains commands " | |||||
| + "from both attribute and child element.", | |||||
| containsAll(output, | |||||
| l -> l.equals("bin/command4"), | |||||
| l -> l.equals("bin/command5"))); | |||||
| } | |||||
| @Test | |||||
| public void testHeaderPath() { | |||||
| buildRule.executeTarget("headerpath"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| Assert.assertTrue("Checking that jmod was successfully created.", | |||||
| jmod.exists()); | |||||
| String output = runJmod("list", jmod.toString()); | |||||
| Assert.assertTrue("Checking that jmod contains header file.", | |||||
| containsLine(output, l -> l.equals("include/header1.h"))); | |||||
| } | |||||
| @Test | |||||
| public void testHeaderPathref() { | |||||
| buildRule.executeTarget("headerpathref"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| Assert.assertTrue("Checking that jmod was successfully created.", | |||||
| jmod.exists()); | |||||
| String output = runJmod("list", jmod.toString()); | |||||
| Assert.assertTrue("Checking that jmod contains header file.", | |||||
| containsLine(output, l -> l.equals("include/header2.h"))); | |||||
| } | |||||
| @Test | |||||
| public void testHeaderPathNested() { | |||||
| buildRule.executeTarget("headerpath-nested"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| Assert.assertTrue("Checking that jmod was successfully created.", | |||||
| jmod.exists()); | |||||
| String output = runJmod("list", jmod.toString()); | |||||
| Assert.assertTrue("Checking that jmod contains header file.", | |||||
| containsLine(output, l -> l.equals("include/header3.h"))); | |||||
| } | |||||
| @Test | |||||
| public void testHeaderPathAttributeAndChildElement() { | |||||
| buildRule.executeTarget("headerpath-both"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| Assert.assertTrue("Checking that jmod was successfully created.", | |||||
| jmod.exists()); | |||||
| String output = runJmod("list", jmod.toString()); | |||||
| Assert.assertTrue("Checking that jmod contains header files " | |||||
| + "from both attribute and child element.", | |||||
| containsAll(output, | |||||
| l -> l.equals("include/header4.h"), | |||||
| l -> l.equals("include/header5.h"))); | |||||
| } | |||||
| @Test | |||||
| public void testConfigPath() { | |||||
| buildRule.executeTarget("configpath"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| Assert.assertTrue("Checking that jmod was successfully created.", | |||||
| jmod.exists()); | |||||
| String output = runJmod("list", jmod.toString()); | |||||
| Assert.assertTrue("Checking that jmod contains config file.", | |||||
| containsLine(output, l -> l.equals("conf/config1.properties"))); | |||||
| } | |||||
| @Test | |||||
| public void testConfigPathref() { | |||||
| buildRule.executeTarget("configpathref"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| Assert.assertTrue("Checking that jmod was successfully created.", | |||||
| jmod.exists()); | |||||
| String output = runJmod("list", jmod.toString()); | |||||
| Assert.assertTrue("Checking that jmod contains config file.", | |||||
| containsLine(output, l -> l.equals("conf/config2.properties"))); | |||||
| } | |||||
| @Test | |||||
| public void testConfigPathNested() { | |||||
| buildRule.executeTarget("configpath-nested"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| Assert.assertTrue("Checking that jmod was successfully created.", | |||||
| jmod.exists()); | |||||
| String output = runJmod("list", jmod.toString()); | |||||
| Assert.assertTrue("Checking that jmod contains config file.", | |||||
| containsLine(output, l -> l.equals("conf/config3.properties"))); | |||||
| } | |||||
| @Test | |||||
| public void testConfigPathAttributeAndChildElement() { | |||||
| buildRule.executeTarget("configpath-both"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| Assert.assertTrue("Checking that jmod was successfully created.", | |||||
| jmod.exists()); | |||||
| String output = runJmod("list", jmod.toString()); | |||||
| Assert.assertTrue("Checking that jmod contains config files " | |||||
| + "from both attribute and child element.", | |||||
| containsAll(output, | |||||
| l -> l.equals("conf/config4.properties"), | |||||
| l -> l.equals("conf/config5.properties"))); | |||||
| } | |||||
| @Test | |||||
| public void testLegalPath() { | |||||
| buildRule.executeTarget("legalpath"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| Assert.assertTrue("Checking that jmod was successfully created.", | |||||
| jmod.exists()); | |||||
| String output = runJmod("list", jmod.toString()); | |||||
| Assert.assertTrue("Checking that jmod contains license file.", | |||||
| containsLine(output, l -> l.equals("legal/legal1.txt"))); | |||||
| } | |||||
| @Test | |||||
| public void testLegalPathref() { | |||||
| buildRule.executeTarget("legalpathref"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| Assert.assertTrue("Checking that jmod was successfully created.", | |||||
| jmod.exists()); | |||||
| String output = runJmod("list", jmod.toString()); | |||||
| Assert.assertTrue("Checking that jmod contains license file.", | |||||
| containsLine(output, l -> l.equals("legal/legal2.txt"))); | |||||
| } | |||||
| @Test | |||||
| public void testLegalPathNested() { | |||||
| buildRule.executeTarget("legalpath-nested"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| Assert.assertTrue("Checking that jmod was successfully created.", | |||||
| jmod.exists()); | |||||
| String output = runJmod("list", jmod.toString()); | |||||
| Assert.assertTrue("Checking that jmod contains license file.", | |||||
| containsLine(output, l -> l.equals("legal/legal3.txt"))); | |||||
| } | |||||
| @Test | |||||
| public void testLegalPathAttributeAndChildElement() { | |||||
| buildRule.executeTarget("legalpath-both"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| Assert.assertTrue("Checking that jmod was successfully created.", | |||||
| jmod.exists()); | |||||
| String output = runJmod("list", jmod.toString()); | |||||
| Assert.assertTrue("Checking that jmod contains legal files " | |||||
| + "from both attribute and child element.", | |||||
| containsAll(output, | |||||
| l -> l.equals("legal/legal4.txt"), | |||||
| l -> l.equals("legal/legal5.txt"))); | |||||
| } | |||||
| @Test | |||||
| public void testManPath() { | |||||
| buildRule.executeTarget("manpath"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| Assert.assertTrue("Checking that jmod was successfully created.", | |||||
| jmod.exists()); | |||||
| String output = runJmod("list", jmod.toString()); | |||||
| Assert.assertTrue("Checking that jmod contains man page.", | |||||
| containsLine(output, l -> l.equals("man/man1.1"))); | |||||
| } | |||||
| @Test | |||||
| public void testManPathref() { | |||||
| buildRule.executeTarget("manpathref"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| Assert.assertTrue("Checking that jmod was successfully created.", | |||||
| jmod.exists()); | |||||
| String output = runJmod("list", jmod.toString()); | |||||
| Assert.assertTrue("Checking that jmod contains man page.", | |||||
| containsLine(output, l -> l.equals("man/man2.1"))); | |||||
| } | |||||
| @Test | |||||
| public void testManPathNested() { | |||||
| buildRule.executeTarget("manpath-nested"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| Assert.assertTrue("Checking that jmod was successfully created.", | |||||
| jmod.exists()); | |||||
| String output = runJmod("list", jmod.toString()); | |||||
| Assert.assertTrue("Checking that jmod contains man page.", | |||||
| containsLine(output, l -> l.equals("man/man3.1"))); | |||||
| } | |||||
| @Test | |||||
| public void testManPathAttributeAndChildElement() { | |||||
| buildRule.executeTarget("manpath-both"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| Assert.assertTrue("Checking that jmod was successfully created.", | |||||
| jmod.exists()); | |||||
| String output = runJmod("list", jmod.toString()); | |||||
| Assert.assertTrue("Checking that jmod contains man pages " | |||||
| + "from both attribute and child element.", | |||||
| containsAll(output, | |||||
| l -> l.equals("man/man4.1"), | |||||
| l -> l.equals("man/man5.1"))); | |||||
| } | |||||
| @Test | |||||
| public void testNativeLibPath() { | |||||
| buildRule.executeTarget("nativelibpath"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| Assert.assertTrue("Checking that jmod was successfully created.", | |||||
| jmod.exists()); | |||||
| String output = runJmod("list", jmod.toString()); | |||||
| Assert.assertTrue("Checking that jmod contains native library.", | |||||
| containsLine(output, l -> l.matches("lib/[^/]+\\.(dll|dylib|so)"))); | |||||
| } | |||||
| @Test | |||||
| public void testNativeLibPathref() { | |||||
| buildRule.executeTarget("nativelibpathref"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| Assert.assertTrue("Checking that jmod was successfully created.", | |||||
| jmod.exists()); | |||||
| String output = runJmod("list", jmod.toString()); | |||||
| Assert.assertTrue("Checking that jmod contains native library.", | |||||
| containsLine(output, l -> l.matches("lib/[^/]+\\.(dll|dylib|so)"))); | |||||
| } | |||||
| @Test | |||||
| public void testNativeLibPathNested() { | |||||
| buildRule.executeTarget("nativelibpath-nested"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| Assert.assertTrue("Checking that jmod was successfully created.", | |||||
| jmod.exists()); | |||||
| String output = runJmod("list", jmod.toString()); | |||||
| Assert.assertTrue("Checking that jmod contains native library.", | |||||
| containsLine(output, l -> l.matches("lib/[^/]+\\.(dll|dylib|so)"))); | |||||
| } | |||||
| @Test | |||||
| public void testNativeLibPathAttributeAndChildElement() { | |||||
| buildRule.executeTarget("nativelibpath-both"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| Assert.assertTrue("Checking that jmod was successfully created.", | |||||
| jmod.exists()); | |||||
| String output = runJmod("list", jmod.toString()); | |||||
| Assert.assertTrue("Checking that jmod contains native libraries " | |||||
| + "from both attribute and child element.", | |||||
| containsAll(output, | |||||
| l -> l.matches("lib/(lib)?zip\\.(dll|dylib|so)"), | |||||
| l -> l.matches("lib/(lib)?jvm\\.(dll|dylib|so)"))); | |||||
| } | |||||
| @Test | |||||
| public void testVersion() { | |||||
| buildRule.executeTarget("version"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| Assert.assertTrue("Checking that jmod was successfully created.", | |||||
| jmod.exists()); | |||||
| String version = buildRule.getProject().getProperty("version"); | |||||
| Assert.assertNotNull("Checking that 'version' property is set", | |||||
| version); | |||||
| Assert.assertFalse("Checking that 'version' property is not empty", | |||||
| version.isEmpty()); | |||||
| String output = runJmod("describe", jmod.toString()); | |||||
| Assert.assertTrue("Checking that jmod has correct version.", | |||||
| containsLine(output, l -> l.endsWith("@" + version))); | |||||
| } | |||||
| @Test | |||||
| public void testNestedVersion() { | |||||
| buildRule.executeTarget("version-nested"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| Assert.assertTrue("Checking that jmod was successfully created.", | |||||
| jmod.exists()); | |||||
| String output = runJmod("describe", jmod.toString()); | |||||
| Assert.assertTrue("Checking that jmod has correct version.", | |||||
| containsLine(output, l -> l.matches(".*@1\\.0\\.1[-+]+99"))); | |||||
| } | |||||
| @Test | |||||
| public void testNestedVersionNumberOnly() { | |||||
| buildRule.executeTarget("version-nested-number"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| Assert.assertTrue("Checking that jmod was successfully created.", | |||||
| jmod.exists()); | |||||
| String output = runJmod("describe", jmod.toString()); | |||||
| Assert.assertTrue("Checking that jmod has correct version.", | |||||
| containsLine(output, l -> l.endsWith("@1.0.1"))); | |||||
| } | |||||
| @Test | |||||
| public void testNestedVersionNoNumber() { | |||||
| expected.expect(BuildException.class); | |||||
| buildRule.executeTarget("version-nested-no-number"); | |||||
| } | |||||
| @Test | |||||
| public void testNestedVersionInvalidNumber() { | |||||
| expected.expect(BuildException.class); | |||||
| buildRule.executeTarget("version-nested-invalid-number"); | |||||
| } | |||||
| @Test | |||||
| public void testNestedVersionInvalidPreRelease() { | |||||
| expected.expect(BuildException.class); | |||||
| buildRule.executeTarget("version-nested-invalid-prerelease"); | |||||
| } | |||||
| @Test | |||||
| public void testVersionAttributeAndChildElement() { | |||||
| expected.expect(BuildException.class); | |||||
| buildRule.executeTarget("version-both"); | |||||
| } | |||||
| @Test | |||||
| public void testMainClass() { | |||||
| buildRule.executeTarget("mainclass"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| Assert.assertTrue("Checking that jmod was successfully created.", | |||||
| jmod.exists()); | |||||
| String mainClass = | |||||
| buildRule.getProject().getProperty("hello.main-class"); | |||||
| Assert.assertNotNull("Checking that 'main-class' property is set", | |||||
| mainClass); | |||||
| Assert.assertFalse("Checking that 'main-class' property is not empty", | |||||
| mainClass.isEmpty()); | |||||
| String output = runJmod("describe", jmod.toString()); | |||||
| String mainClassPattern = "main-class\\s+" + Pattern.quote(mainClass); | |||||
| Assert.assertTrue("Checking that jmod has correct main class.", | |||||
| containsLine(output, l -> l.matches(mainClassPattern))); | |||||
| } | |||||
| @Test | |||||
| public void testPlatform() { | |||||
| buildRule.executeTarget("platform"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| Assert.assertTrue("Checking that jmod was successfully created.", | |||||
| jmod.exists()); | |||||
| String platform = buildRule.getProject().getProperty("target-platform"); | |||||
| Assert.assertNotNull("Checking that 'target-platform' property is set", | |||||
| platform); | |||||
| Assert.assertFalse("Checking that 'target-platform' property " | |||||
| + "is not empty", platform.isEmpty()); | |||||
| String output = runJmod("describe", jmod.toString()); | |||||
| String platformPattern = "platform\\s+" + Pattern.quote(platform); | |||||
| Assert.assertTrue("Checking that jmod has correct main class.", | |||||
| containsLine(output, l -> l.matches(platformPattern))); | |||||
| } | |||||
| @Test | |||||
| public void testHashing() { | |||||
| buildRule.executeTarget("hashing"); | |||||
| File jmod = new File(buildRule.getProject().getProperty("jmod")); | |||||
| Assert.assertTrue("Checking that jmod was successfully created.", | |||||
| jmod.exists()); | |||||
| String output = runJmod("describe", jmod.toString()); | |||||
| Assert.assertTrue("Checking that jmod has module hashes.", | |||||
| containsLine(output, l -> l.startsWith("hashes"))); | |||||
| } | |||||
| private String runJmod(final String... args) { | |||||
| ToolProvider jmod = ToolProvider.findFirst("jmod").orElseThrow( | |||||
| () -> new RuntimeException("jmod tool not found in JDK.")); | |||||
| ByteArrayOutputStream stdout = new ByteArrayOutputStream(); | |||||
| ByteArrayOutputStream stderr = new ByteArrayOutputStream(); | |||||
| int exitCode; | |||||
| try (PrintStream out = new PrintStream(stdout); | |||||
| PrintStream err = new PrintStream(stderr)) { | |||||
| exitCode = jmod.run(out, err, args); | |||||
| } | |||||
| if (exitCode != 0) { | |||||
| throw new RuntimeException( | |||||
| "jmod failed, output is: " + stdout + ", error is: " + stderr); | |||||
| } | |||||
| return stdout.toString(); | |||||
| } | |||||
| private boolean containsLine(final String lines, | |||||
| final Predicate<? super String> test) { | |||||
| try (BufferedReader reader = | |||||
| new BufferedReader(new StringReader(lines))) { | |||||
| return reader.lines().anyMatch(test); | |||||
| } catch (IOException e) { | |||||
| throw new RuntimeException(e); | |||||
| } | |||||
| } | |||||
| private boolean containsAll(final String lines, | |||||
| final Predicate<? super String> test1, | |||||
| final Predicate<? super String> test2) { | |||||
| try (BufferedReader reader = | |||||
| new BufferedReader(new StringReader(lines))) { | |||||
| boolean test1Matched = false; | |||||
| boolean test2Matched = false; | |||||
| String line; | |||||
| while ((line = reader.readLine()) != null) { | |||||
| test1Matched |= test1.test(line); | |||||
| test2Matched |= test2.test(line); | |||||
| } | |||||
| return test1Matched && test2Matched; | |||||
| } catch (IOException e) { | |||||
| throw new RuntimeException(e); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,984 @@ | |||||
| /* | |||||
| * 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 | |||||
| * | |||||
| * http://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. | |||||
| * | |||||
| */ | |||||
| package org.apache.tools.ant.taskdefs.modules; | |||||
| import java.io.ByteArrayOutputStream; | |||||
| import java.io.PrintStream; | |||||
| import java.io.BufferedReader; | |||||
| import java.io.InputStreamReader; | |||||
| import java.io.FileReader; | |||||
| import java.io.StringReader; | |||||
| import java.io.File; | |||||
| import java.io.IOException; | |||||
| import java.io.UncheckedIOException; | |||||
| import java.nio.file.DirectoryStream; | |||||
| import java.nio.file.Files; | |||||
| import java.nio.file.Path; | |||||
| import java.time.Instant; | |||||
| import java.time.temporal.ChronoUnit; | |||||
| import java.util.Collection; | |||||
| import java.util.stream.Collectors; | |||||
| import java.util.stream.Stream; | |||||
| import java.util.spi.ToolProvider; | |||||
| import org.junit.Assert; | |||||
| import org.junit.Assume; | |||||
| import org.junit.Before; | |||||
| import org.junit.Rule; | |||||
| import org.junit.Test; | |||||
| import org.junit.rules.ExpectedException; | |||||
| import org.apache.tools.ant.BuildException; | |||||
| import org.apache.tools.ant.BuildFileRule; | |||||
| /** | |||||
| * Tests the {@link Link} task. | |||||
| */ | |||||
| public class LinkTest { | |||||
| /* | |||||
| * TODO: | |||||
| * Test --order-resources (how?) | |||||
| * Test --exclude-files (what does this actually do?) | |||||
| * Test --endian (how?) | |||||
| * Test --vm (how?) | |||||
| */ | |||||
| @Rule | |||||
| public final BuildFileRule buildRule = new BuildFileRule(); | |||||
| @Rule | |||||
| public final ExpectedException expected = ExpectedException.none(); | |||||
| @Before | |||||
| public void setUp() { | |||||
| buildRule.configureProject("src/etc/testcases/taskdefs/link.xml"); | |||||
| buildRule.executeTarget("setUp"); | |||||
| } | |||||
| private static boolean isWindows() { | |||||
| return System.getProperty("os.name").contains("Windows"); | |||||
| } | |||||
| private static boolean isEarlierThan(final Instant time, | |||||
| final Path path) { | |||||
| try { | |||||
| return Files.getLastModifiedTime(path).toInstant().isBefore(time); | |||||
| } catch (IOException e) { | |||||
| throw new UncheckedIOException(e); | |||||
| } | |||||
| } | |||||
| private static class ImageStructure { | |||||
| final File root; | |||||
| final File bin; | |||||
| final File java; | |||||
| ImageStructure(final File root) { | |||||
| this.root = root; | |||||
| bin = new File(root, "bin"); | |||||
| java = new File(bin, isWindows() ? "java.exe" : "java"); | |||||
| } | |||||
| } | |||||
| private ImageStructure verifyImageBuiltNormally() { | |||||
| ImageStructure image = new ImageStructure( | |||||
| new File(buildRule.getProject().getProperty("image"))); | |||||
| Assert.assertTrue("Checking that image was successfully created.", | |||||
| image.root.exists()); | |||||
| Assert.assertTrue("Checking that image has java executable.", | |||||
| image.java.exists()); | |||||
| return image; | |||||
| } | |||||
| @Test | |||||
| public void testModulepath() { | |||||
| buildRule.executeTarget("modulepath"); | |||||
| verifyImageBuiltNormally(); | |||||
| } | |||||
| @Test | |||||
| public void testImageNotRecreatedFromStaleJmods() | |||||
| throws IOException { | |||||
| buildRule.executeTarget("imageNewerThanJmods"); | |||||
| ImageStructure image = verifyImageBuiltNormally(); | |||||
| Instant future = Instant.now().plus(30, ChronoUnit.MINUTES); | |||||
| try (Stream<Path> imageFiles = Files.walk(image.root.toPath())) { | |||||
| Assert.assertTrue("Checking that newer image was not written " | |||||
| + "when source files are older.", | |||||
| imageFiles.noneMatch(i -> isEarlierThan(future, i))); | |||||
| } | |||||
| } | |||||
| @Test | |||||
| public void testNoModulePath() { | |||||
| expected.expect(BuildException.class); | |||||
| buildRule.executeTarget("nomodulepath"); | |||||
| } | |||||
| @Test | |||||
| public void testNoModules() { | |||||
| expected.expect(BuildException.class); | |||||
| buildRule.executeTarget("nomodules"); | |||||
| } | |||||
| @Test | |||||
| public void testModulePathRef() { | |||||
| buildRule.executeTarget("modulepathref"); | |||||
| verifyImageBuiltNormally(); | |||||
| } | |||||
| @Test | |||||
| public void testNestedModulePath() { | |||||
| buildRule.executeTarget("modulepath-nested"); | |||||
| verifyImageBuiltNormally(); | |||||
| } | |||||
| @Test | |||||
| public void testModulePathInAttributeAndNested() { | |||||
| buildRule.executeTarget("modulepath-both"); | |||||
| verifyImageBuiltNormally(); | |||||
| } | |||||
| @Test | |||||
| public void testNestedModules() | |||||
| throws IOException, | |||||
| InterruptedException { | |||||
| buildRule.executeTarget("modules-nested"); | |||||
| ImageStructure image = verifyImageBuiltNormally(); | |||||
| ProcessBuilder builder = new ProcessBuilder( | |||||
| image.java.toString(), | |||||
| buildRule.getProject().getProperty("hello.main-class")); | |||||
| builder.inheritIO(); | |||||
| int exitCode = builder.start().waitFor(); | |||||
| Assert.assertEquals( | |||||
| "Checking that execution of first module succeeded.", 0, exitCode); | |||||
| builder.command( | |||||
| image.java.toString(), | |||||
| buildRule.getProject().getProperty("smile.main-class")); | |||||
| exitCode = builder.start().waitFor(); | |||||
| Assert.assertEquals( | |||||
| "Checking that execution of second module succeeded.", 0, exitCode); | |||||
| } | |||||
| @Test | |||||
| public void testNestedModuleMissingName() { | |||||
| expected.expect(BuildException.class); | |||||
| buildRule.executeTarget("modules-nested-missing-name"); | |||||
| } | |||||
| @Test | |||||
| public void testModulesInAttributeAndNested() { | |||||
| buildRule.executeTarget("modules-both"); | |||||
| verifyImageBuiltNormally(); | |||||
| } | |||||
| @Test | |||||
| public void testObservableModules() { | |||||
| expected.expect(BuildException.class); | |||||
| buildRule.executeTarget("observable"); | |||||
| } | |||||
| @Test | |||||
| public void testNestedObservableModules() { | |||||
| expected.expect(BuildException.class); | |||||
| buildRule.executeTarget("observable-nested"); | |||||
| } | |||||
| @Test | |||||
| public void testNestedObservableModuleMissingName() { | |||||
| expected.expect(BuildException.class); | |||||
| buildRule.executeTarget("observable-nested-missing-name"); | |||||
| } | |||||
| @Test | |||||
| public void testObservableModulesInAttributeAndNested() { | |||||
| buildRule.executeTarget("observable-both"); | |||||
| verifyImageBuiltNormally(); | |||||
| } | |||||
| private void verifyLaunchersExist() { | |||||
| ImageStructure image = verifyImageBuiltNormally(); | |||||
| File launcher1 = | |||||
| new File(image.bin, isWindows() ? "Hello.bat" : "Hello"); | |||||
| Assert.assertTrue("Checking that image has 'Hello' launcher.", | |||||
| launcher1.exists()); | |||||
| File launcher2 = | |||||
| new File(image.bin, isWindows() ? "Smile.bat" : "Smile"); | |||||
| Assert.assertTrue("Checking that image has 'Smile' launcher.", | |||||
| launcher2.exists()); | |||||
| } | |||||
| @Test | |||||
| public void testLaunchers() { | |||||
| buildRule.executeTarget("launchers"); | |||||
| verifyLaunchersExist(); | |||||
| } | |||||
| @Test | |||||
| public void testNestedLaunchers() { | |||||
| buildRule.executeTarget("launchers-nested"); | |||||
| verifyLaunchersExist(); | |||||
| } | |||||
| @Test | |||||
| public void testNestedLauncherMissingName() { | |||||
| expected.expect(BuildException.class); | |||||
| buildRule.executeTarget("launchers-nested-missing-name"); | |||||
| } | |||||
| @Test | |||||
| public void testNestedLauncherMissingModule() { | |||||
| expected.expect(BuildException.class); | |||||
| buildRule.executeTarget("launchers-nested-missing-module"); | |||||
| } | |||||
| @Test | |||||
| public void testLaunchersInAttributeAndNested() { | |||||
| buildRule.executeTarget("launchers-both"); | |||||
| verifyLaunchersExist(); | |||||
| } | |||||
| private void verifyLocales() | |||||
| throws IOException, | |||||
| InterruptedException { | |||||
| ImageStructure image = verifyImageBuiltNormally(); | |||||
| String mainClass = | |||||
| buildRule.getProject().getProperty("localefinder.main-class"); | |||||
| Assert.assertNotNull("Checking that main-class property exists", | |||||
| mainClass); | |||||
| ProcessBuilder builder = | |||||
| new ProcessBuilder(image.java.toString(), mainClass, "zh", "in"); | |||||
| builder.inheritIO(); | |||||
| int exitCode = builder.start().waitFor(); | |||||
| Assert.assertEquals("Verifying that image has access to locales " | |||||
| + "specified during linking.", 0, exitCode); | |||||
| builder.command(image.java.toString(), mainClass, "ja"); | |||||
| exitCode = builder.start().waitFor(); | |||||
| Assert.assertNotEquals( | |||||
| "Verifying that image does not have access to locales " | |||||
| + "not specified during linking.", 0, exitCode); | |||||
| } | |||||
| @Test | |||||
| public void testLocales() | |||||
| throws IOException, | |||||
| InterruptedException { | |||||
| buildRule.executeTarget("locales"); | |||||
| verifyLocales(); | |||||
| } | |||||
| @Test | |||||
| public void testNestedLocales() | |||||
| throws IOException, | |||||
| InterruptedException { | |||||
| buildRule.executeTarget("locales-nested"); | |||||
| verifyLocales(); | |||||
| } | |||||
| @Test | |||||
| public void testNestedLocaleMissingName() { | |||||
| expected.expect(BuildException.class); | |||||
| buildRule.executeTarget("locales-nested-missing-name"); | |||||
| } | |||||
| @Test | |||||
| public void testLocalesInAttributeAndNested() | |||||
| throws IOException, | |||||
| InterruptedException { | |||||
| buildRule.executeTarget("locales-both"); | |||||
| verifyLocales(); | |||||
| } | |||||
| @Test | |||||
| public void testExcludeResources() | |||||
| throws IOException { | |||||
| buildRule.executeTarget("excluderesources"); | |||||
| ImageStructure image = verifyImageBuiltNormally(); | |||||
| String mainClass = | |||||
| buildRule.getProject().getProperty("hello.main-class"); | |||||
| Assert.assertNotNull("Checking that main-class property exists", | |||||
| mainClass); | |||||
| ProcessBuilder builder = | |||||
| new ProcessBuilder(image.java.toString(), mainClass, | |||||
| "resource1.txt", "resource2.txt"); | |||||
| builder.redirectInput(ProcessBuilder.Redirect.INHERIT); | |||||
| builder.redirectErrorStream(true); | |||||
| Collection<String> outputLines; | |||||
| Process process = builder.start(); | |||||
| try (BufferedReader reader = new BufferedReader( | |||||
| new InputStreamReader(process.getInputStream()))) { | |||||
| outputLines = reader.lines().collect(Collectors.toList()); | |||||
| } | |||||
| Assert.assertTrue( | |||||
| "Checking that excluded resource is actually excluded.", | |||||
| outputLines.stream().anyMatch( | |||||
| l -> l.endsWith("resource1.txt absent"))); | |||||
| Assert.assertTrue( | |||||
| "Checking that resource not excluded is present.", | |||||
| outputLines.stream().anyMatch( | |||||
| l -> l.endsWith("resource2.txt present"))); | |||||
| } | |||||
| @Test | |||||
| public void testNestedExcludeResources() | |||||
| throws IOException { | |||||
| buildRule.executeTarget("excluderesources-nested"); | |||||
| ImageStructure image = verifyImageBuiltNormally(); | |||||
| String mainClass = | |||||
| buildRule.getProject().getProperty("hello.main-class"); | |||||
| Assert.assertNotNull("Checking that main-class property exists", | |||||
| mainClass); | |||||
| ProcessBuilder builder = | |||||
| new ProcessBuilder(image.java.toString(), mainClass, | |||||
| "resource1.txt", "resource2.txt"); | |||||
| builder.redirectInput(ProcessBuilder.Redirect.INHERIT); | |||||
| builder.redirectErrorStream(true); | |||||
| Collection<String> outputLines; | |||||
| Process process = builder.start(); | |||||
| try (BufferedReader reader = new BufferedReader( | |||||
| new InputStreamReader(process.getInputStream()))) { | |||||
| outputLines = reader.lines().collect(Collectors.toList()); | |||||
| } | |||||
| Assert.assertTrue( | |||||
| "Checking that excluded resource is actually excluded.", | |||||
| outputLines.stream().anyMatch( | |||||
| l -> l.endsWith("resource1.txt absent"))); | |||||
| Assert.assertTrue( | |||||
| "Checking that resource not excluded is present.", | |||||
| outputLines.stream().anyMatch( | |||||
| l -> l.endsWith("resource2.txt present"))); | |||||
| } | |||||
| @Test | |||||
| public void testNestedExcludeResourcesFile() | |||||
| throws IOException { | |||||
| buildRule.executeTarget("excluderesources-nested-file"); | |||||
| ImageStructure image = verifyImageBuiltNormally(); | |||||
| String mainClass = | |||||
| buildRule.getProject().getProperty("hello.main-class"); | |||||
| Assert.assertNotNull("Checking that main-class property exists", | |||||
| mainClass); | |||||
| ProcessBuilder builder = | |||||
| new ProcessBuilder(image.java.toString(), mainClass, | |||||
| "resource1.txt", "resource2.txt"); | |||||
| builder.redirectInput(ProcessBuilder.Redirect.INHERIT); | |||||
| builder.redirectErrorStream(true); | |||||
| Collection<String> outputLines; | |||||
| Process process = builder.start(); | |||||
| try (BufferedReader reader = new BufferedReader( | |||||
| new InputStreamReader(process.getInputStream()))) { | |||||
| outputLines = reader.lines().collect(Collectors.toList()); | |||||
| } | |||||
| Assert.assertTrue( | |||||
| "Checking that excluded resource is actually excluded.", | |||||
| outputLines.stream().anyMatch( | |||||
| l -> l.endsWith("resource1.txt absent"))); | |||||
| Assert.assertTrue( | |||||
| "Checking that resource not excluded is present.", | |||||
| outputLines.stream().anyMatch( | |||||
| l -> l.endsWith("resource2.txt present"))); | |||||
| } | |||||
| @Test | |||||
| public void testNestedExcludeResourcesNoAttributes() { | |||||
| expected.expect(BuildException.class); | |||||
| buildRule.executeTarget("excluderesources-nested-no-attr"); | |||||
| } | |||||
| @Test | |||||
| public void testNestedExcludeResourcesFileAndPattern() { | |||||
| expected.expect(BuildException.class); | |||||
| buildRule.executeTarget("excluderesources-nested-both"); | |||||
| } | |||||
| @Test | |||||
| public void testExcludeResourcesAttributeAndNested() | |||||
| throws IOException { | |||||
| buildRule.executeTarget("excluderesources-both"); | |||||
| ImageStructure image = verifyImageBuiltNormally(); | |||||
| String mainClass = | |||||
| buildRule.getProject().getProperty("hello.main-class"); | |||||
| Assert.assertNotNull("Checking that main-class property exists", | |||||
| mainClass); | |||||
| ProcessBuilder builder = | |||||
| new ProcessBuilder(image.java.toString(), mainClass, | |||||
| "resource1.txt", "resource2.txt"); | |||||
| builder.redirectInput(ProcessBuilder.Redirect.INHERIT); | |||||
| builder.redirectErrorStream(true); | |||||
| Collection<String> outputLines; | |||||
| Process process = builder.start(); | |||||
| try (BufferedReader reader = new BufferedReader( | |||||
| new InputStreamReader(process.getInputStream()))) { | |||||
| outputLines = reader.lines().collect(Collectors.toList()); | |||||
| } | |||||
| Assert.assertTrue( | |||||
| "Checking that first excluded resource is actually excluded.", | |||||
| outputLines.stream().anyMatch( | |||||
| l -> l.endsWith("resource1.txt absent"))); | |||||
| Assert.assertTrue( | |||||
| "Checking that second excluded resource is actually excluded.", | |||||
| outputLines.stream().anyMatch( | |||||
| l -> l.endsWith("resource2.txt absent"))); | |||||
| } | |||||
| @Test | |||||
| public void testExcludeFiles() | |||||
| throws IOException { | |||||
| buildRule.executeTarget("excludefiles"); | |||||
| verifyImageBuiltNormally(); | |||||
| // TODO: Test created image (what does --exclude-files actually do?) | |||||
| } | |||||
| @Test | |||||
| public void testNestedExcludeFiles() | |||||
| throws IOException { | |||||
| buildRule.executeTarget("excludefiles-nested"); | |||||
| verifyImageBuiltNormally(); | |||||
| // TODO: Test created image (what does --exclude-files actually do?) | |||||
| } | |||||
| @Test | |||||
| public void testNestedExcludeFilesFile() | |||||
| throws IOException { | |||||
| buildRule.executeTarget("excludefiles-nested-file"); | |||||
| ImageStructure image = verifyImageBuiltNormally(); | |||||
| // TODO: Test created image (what does --exclude-files actually do?) | |||||
| } | |||||
| @Test | |||||
| public void testNestedExcludeFilesNoAttributes() { | |||||
| expected.expect(BuildException.class); | |||||
| buildRule.executeTarget("excludefiles-nested-no-attr"); | |||||
| } | |||||
| @Test | |||||
| public void testNestedExcludeFilesFileAndPattern() { | |||||
| expected.expect(BuildException.class); | |||||
| buildRule.executeTarget("excludefiles-nested-both"); | |||||
| } | |||||
| @Test | |||||
| public void testExcludeFilesAttributeAndNested() | |||||
| throws IOException { | |||||
| buildRule.executeTarget("excludefiles-both"); | |||||
| verifyImageBuiltNormally(); | |||||
| // TODO: Test created image (what does --exclude-files actually do?) | |||||
| } | |||||
| @Test | |||||
| public void testOrdering() | |||||
| throws IOException { | |||||
| buildRule.executeTarget("ordering"); | |||||
| verifyImageBuiltNormally(); | |||||
| // TODO: Test resource order in created image (how?) | |||||
| } | |||||
| @Test | |||||
| public void testNestedOrdering() | |||||
| throws IOException { | |||||
| buildRule.executeTarget("ordering-nested"); | |||||
| verifyImageBuiltNormally(); | |||||
| // TODO: Test resource order in created image (how?) | |||||
| } | |||||
| @Test | |||||
| public void testNestedOrderingListFile() | |||||
| throws IOException { | |||||
| buildRule.executeTarget("ordering-nested-file"); | |||||
| ImageStructure image = verifyImageBuiltNormally(); | |||||
| // TODO: Test resource order in created image (how?) | |||||
| } | |||||
| @Test | |||||
| public void testNestedOrderingNoAttributes() { | |||||
| expected.expect(BuildException.class); | |||||
| buildRule.executeTarget("ordering-nested-no-attr"); | |||||
| } | |||||
| @Test | |||||
| public void testNestedOrderingFileAndPattern() { | |||||
| expected.expect(BuildException.class); | |||||
| buildRule.executeTarget("ordering-nested-both"); | |||||
| } | |||||
| @Test | |||||
| public void testOrderingAttributeAndNested() | |||||
| throws IOException { | |||||
| buildRule.executeTarget("ordering-both"); | |||||
| verifyImageBuiltNormally(); | |||||
| // TODO: Test resource order in created image (how?) | |||||
| } | |||||
| @Test | |||||
| public void testIncludeHeaders() { | |||||
| buildRule.executeTarget("includeheaders"); | |||||
| ImageStructure image = verifyImageBuiltNormally(); | |||||
| File[] headers = new File(image.root, "include").listFiles(); | |||||
| Assert.assertTrue("Checking that include files were omitted.", | |||||
| headers == null || headers.length == 0); | |||||
| } | |||||
| @Test | |||||
| public void testIncludeManPages() { | |||||
| buildRule.executeTarget("includemanpages"); | |||||
| ImageStructure image = verifyImageBuiltNormally(); | |||||
| File[] manPages = new File(image.root, "man").listFiles(); | |||||
| Assert.assertTrue("Checking that man pages were omitted.", | |||||
| manPages == null || manPages.length == 0); | |||||
| } | |||||
| @Test | |||||
| public void testIncludeNativeCommands() { | |||||
| buildRule.executeTarget("includenativecommands"); | |||||
| ImageStructure image = new ImageStructure( | |||||
| new File(buildRule.getProject().getProperty("image"))); | |||||
| Assert.assertTrue("Checking that image was successfully created.", | |||||
| image.root.exists()); | |||||
| Assert.assertFalse( | |||||
| "Checking that image was stripped of java executable.", | |||||
| image.java.exists()); | |||||
| } | |||||
| private long totalSizeOf(final Path path) | |||||
| throws IOException { | |||||
| if (Files.isDirectory(path)) { | |||||
| long size = 0; | |||||
| try (DirectoryStream<Path> children = Files.newDirectoryStream(path)) { | |||||
| for (Path child : children) { | |||||
| size += totalSizeOf(child); | |||||
| } | |||||
| } | |||||
| return size; | |||||
| } | |||||
| if (Files.isRegularFile(path)) { | |||||
| return Files.size(path); | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| @Test | |||||
| public void testCompression() | |||||
| throws IOException { | |||||
| buildRule.executeTarget("compression"); | |||||
| ImageStructure image = verifyImageBuiltNormally(); | |||||
| File compressedImageRoot = | |||||
| new File(buildRule.getProject().getProperty("compressed-image")); | |||||
| long size = totalSizeOf(image.root.toPath()); | |||||
| long compressedSize = totalSizeOf(compressedImageRoot.toPath()); | |||||
| Assert.assertTrue("Checking that compression resulted in smaller image.", | |||||
| compressedSize < size); | |||||
| } | |||||
| @Test | |||||
| public void testNestedCompression() | |||||
| throws IOException { | |||||
| buildRule.executeTarget("compression-nested"); | |||||
| ImageStructure image = verifyImageBuiltNormally(); | |||||
| File compressedImageRoot = | |||||
| new File(buildRule.getProject().getProperty("compressed-image")); | |||||
| long size = totalSizeOf(image.root.toPath()); | |||||
| long compressedSize = totalSizeOf(compressedImageRoot.toPath()); | |||||
| Assert.assertTrue("Checking that compression resulted in smaller image.", | |||||
| compressedSize < size); | |||||
| } | |||||
| @Test | |||||
| public void testNestedCompressionNoAttributes() { | |||||
| expected.expect(BuildException.class); | |||||
| buildRule.executeTarget("compression-nested-no-attr"); | |||||
| } | |||||
| @Test | |||||
| public void testNestedCompressionAttributeAndNested() { | |||||
| expected.expect(BuildException.class); | |||||
| buildRule.executeTarget("compression-both"); | |||||
| } | |||||
| @Test | |||||
| public void testEndian() { | |||||
| buildRule.executeTarget("endian"); | |||||
| verifyImageBuiltNormally(); | |||||
| // TODO: How can we test the created image? Which files does --endian | |||||
| // affect? | |||||
| } | |||||
| @Test | |||||
| public void testVMType() { | |||||
| buildRule.executeTarget("vm"); | |||||
| verifyImageBuiltNormally(); | |||||
| // TODO: How can we test the created image? Which files does --vm | |||||
| // affect? | |||||
| } | |||||
| @Test | |||||
| public void testReleaseInfoFile() | |||||
| throws IOException { | |||||
| buildRule.executeTarget("releaseinfo-file"); | |||||
| ImageStructure image = verifyImageBuiltNormally(); | |||||
| File release = new File(image.root, "release"); | |||||
| try (BufferedReader reader = | |||||
| Files.newBufferedReader(release.toPath())) { | |||||
| Assert.assertTrue("Checking for 'test=true' in image release info.", | |||||
| reader.lines().anyMatch(l -> l.equals("test=true"))); | |||||
| } | |||||
| } | |||||
| @Test | |||||
| public void testReleaseInfoDelete() | |||||
| throws IOException { | |||||
| buildRule.executeTarget("releaseinfo-delete"); | |||||
| ImageStructure image = verifyImageBuiltNormally(); | |||||
| File release = new File(image.root, "release"); | |||||
| try (BufferedReader reader = | |||||
| Files.newBufferedReader(release.toPath())) { | |||||
| Assert.assertFalse("Checking that 'test' was deleted " | |||||
| + "from image release info.", | |||||
| reader.lines().anyMatch(l -> l.startsWith("test="))); | |||||
| } | |||||
| } | |||||
| @Test | |||||
| public void testReleaseInfoNestedDelete() | |||||
| throws IOException { | |||||
| buildRule.executeTarget("releaseinfo-nested-delete"); | |||||
| ImageStructure image = verifyImageBuiltNormally(); | |||||
| File release = new File(image.root, "release"); | |||||
| try (BufferedReader reader = | |||||
| Files.newBufferedReader(release.toPath())) { | |||||
| Assert.assertFalse("Checking that 'test' was deleted " | |||||
| + "from image release info.", | |||||
| reader.lines().anyMatch(l -> l.startsWith("test="))); | |||||
| } | |||||
| } | |||||
| @Test | |||||
| public void testReleaseInfoNestedDeleteNoKey() { | |||||
| expected.expect(BuildException.class); | |||||
| buildRule.executeTarget("releaseinfo-nested-delete-no-key"); | |||||
| } | |||||
| @Test | |||||
| public void testReleaseInfoDeleteAttributeAndNested() | |||||
| throws IOException { | |||||
| buildRule.executeTarget("releaseinfo-nested-delete-both"); | |||||
| ImageStructure image = verifyImageBuiltNormally(); | |||||
| File release = new File(image.root, "release"); | |||||
| try (BufferedReader reader = | |||||
| Files.newBufferedReader(release.toPath())) { | |||||
| Assert.assertTrue( | |||||
| "Checking that 'test' and 'foo' were deleted " | |||||
| + "from image release info.", | |||||
| reader.lines().noneMatch(l -> | |||||
| l.startsWith("test=") || l.startsWith("foo="))); | |||||
| } | |||||
| } | |||||
| @Test | |||||
| public void testReleaseInfoAddFile() | |||||
| throws IOException { | |||||
| buildRule.executeTarget("releaseinfo-add-file"); | |||||
| ImageStructure image = verifyImageBuiltNormally(); | |||||
| File release = new File(image.root, "release"); | |||||
| try (BufferedReader reader = new BufferedReader( | |||||
| new FileReader(release))) { | |||||
| Assert.assertTrue("Checking that 'test=s\u00ed' was added " | |||||
| + "to image release info.", | |||||
| reader.lines().anyMatch(l -> l.equals("test=s\u00ed"))); | |||||
| } | |||||
| } | |||||
| @Test | |||||
| public void testReleaseInfoAddFileWithCharset() | |||||
| throws IOException { | |||||
| buildRule.executeTarget("releaseinfo-add-file-charset"); | |||||
| ImageStructure image = verifyImageBuiltNormally(); | |||||
| File release = new File(image.root, "release"); | |||||
| // Using FileReader here since 'release' file is in platform's charset. | |||||
| try (BufferedReader reader = new BufferedReader( | |||||
| new FileReader(release))) { | |||||
| Assert.assertTrue("Checking that 'test=s\u00ed' was added " | |||||
| + "to image release info.", | |||||
| reader.lines().anyMatch(l -> l.equals("test=s\u00ed"))); | |||||
| } | |||||
| } | |||||
| @Test | |||||
| public void testReleaseInfoAddKeyAndValue() | |||||
| throws IOException { | |||||
| buildRule.executeTarget("releaseinfo-add-key"); | |||||
| ImageStructure image = verifyImageBuiltNormally(); | |||||
| File release = new File(image.root, "release"); | |||||
| try (BufferedReader reader = | |||||
| Files.newBufferedReader(release.toPath())) { | |||||
| Assert.assertTrue("Checking that 'test=true' was added " | |||||
| + "to image release info.", | |||||
| reader.lines().anyMatch(l -> l.equals("test=true"))); | |||||
| } | |||||
| } | |||||
| @Test | |||||
| public void testReleaseInfoAddNoValue() { | |||||
| expected.expect(BuildException.class); | |||||
| buildRule.executeTarget("releaseinfo-add-no-value"); | |||||
| } | |||||
| @Test | |||||
| public void testReleaseInfoAddNoKey() { | |||||
| expected.expect(BuildException.class); | |||||
| buildRule.executeTarget("releaseinfo-add-no-key"); | |||||
| } | |||||
| @Test | |||||
| public void testReleaseInfoAddFileAndKey() { | |||||
| expected.expect(BuildException.class); | |||||
| buildRule.executeTarget("releaseinfo-add-file-and-key"); | |||||
| } | |||||
| @Test | |||||
| public void testReleaseInfoAddFileAndValue() { | |||||
| expected.expect(BuildException.class); | |||||
| buildRule.executeTarget("releaseinfo-add-file-and-value"); | |||||
| } | |||||
| @Test | |||||
| public void testDebugStripping() | |||||
| throws IOException, | |||||
| InterruptedException { | |||||
| buildRule.executeTarget("debug"); | |||||
| ImageStructure image = verifyImageBuiltNormally(); | |||||
| ProcessBuilder builder = new ProcessBuilder( | |||||
| image.java.toString(), | |||||
| buildRule.getProject().getProperty("thrower.main-class")); | |||||
| builder.redirectInput(ProcessBuilder.Redirect.INHERIT); | |||||
| builder.redirectErrorStream(true); | |||||
| Process process = builder.start(); | |||||
| try (BufferedReader linesReader = new BufferedReader( | |||||
| new InputStreamReader(process.getInputStream()))) { | |||||
| Assert.assertTrue( | |||||
| "Checking that stack trace contains no debug information.", | |||||
| linesReader.lines().noneMatch( | |||||
| l -> l.matches(".*\\([^)]*:[0-9]+\\)"))); | |||||
| } | |||||
| process.waitFor(); | |||||
| } | |||||
| @Test | |||||
| public void testDeduplicationOfLicenses() { | |||||
| buildRule.executeTarget("dedup"); | |||||
| ImageStructure image = verifyImageBuiltNormally(); | |||||
| String helloModuleName = | |||||
| buildRule.getProject().getProperty("hello.mod"); | |||||
| String smileModuleName = | |||||
| buildRule.getProject().getProperty("smile.mod"); | |||||
| Assert.assertNotNull("Checking that 'hello.mod' property was set.", | |||||
| helloModuleName); | |||||
| Assert.assertNotNull("Checking that 'smile.mod' property was set.", | |||||
| smileModuleName); | |||||
| Assume.assumeFalse("Checking that this operating system" | |||||
| + " supports symbolic links as a means of license de-duplication.", | |||||
| System.getProperty("os.name").contains("Windows")); | |||||
| Path legal = image.root.toPath().resolve("legal"); | |||||
| Path[] licenses = { | |||||
| legal.resolve(helloModuleName).resolve("USELESSLICENSE"), | |||||
| legal.resolve(smileModuleName).resolve("USELESSLICENSE"), | |||||
| }; | |||||
| int nonLinkCount = 0; | |||||
| for (Path license : licenses) { | |||||
| if (!Files.isSymbolicLink(license)) { | |||||
| nonLinkCount++; | |||||
| } | |||||
| } | |||||
| Assert.assertEquals( | |||||
| "Checking that USELESSLICENSE only exists once in image " | |||||
| + "and all other instances are links to it.", | |||||
| 1, nonLinkCount); | |||||
| } | |||||
| @Test | |||||
| public void testIgnoreSigning() { | |||||
| buildRule.executeTarget("ignoresigning"); | |||||
| verifyImageBuiltNormally(); | |||||
| } | |||||
| /** | |||||
| * Should fail due to jlink rejecting identically named files whose | |||||
| * contents are different. | |||||
| */ | |||||
| @Test | |||||
| public void testDeduplicationOfInconsistentLicenses() { | |||||
| expected.expect(BuildException.class); | |||||
| buildRule.executeTarget("dedup-identical"); | |||||
| } | |||||
| @Test | |||||
| public void testBindingOfServices() | |||||
| throws IOException, | |||||
| InterruptedException { | |||||
| buildRule.executeTarget("bindservices"); | |||||
| ImageStructure image = verifyImageBuiltNormally(); | |||||
| String mainClass = buildRule.getProject().getProperty("inc.main-class"); | |||||
| ProcessBuilder builder = new ProcessBuilder( | |||||
| image.java.toString(), mainClass); | |||||
| builder.redirectInput(ProcessBuilder.Redirect.INHERIT); | |||||
| builder.redirectError(ProcessBuilder.Redirect.INHERIT); | |||||
| Process process = builder.start(); | |||||
| try (BufferedReader linesReader = new BufferedReader( | |||||
| new InputStreamReader(process.getInputStream()))) { | |||||
| Assert.assertEquals( | |||||
| "Checking that bindServices=false results in no providers in image.", | |||||
| 0, linesReader.lines().count()); | |||||
| } | |||||
| process.waitFor(); | |||||
| image = new ImageStructure( | |||||
| new File(buildRule.getProject().getProperty("image2"))); | |||||
| Assert.assertTrue("Checking that image2 was successfully created.", | |||||
| image.root.exists()); | |||||
| Assert.assertTrue("Checking that image2 has java executable.", | |||||
| image.java.exists()); | |||||
| builder = new ProcessBuilder(image.java.toString(), mainClass); | |||||
| builder.redirectInput(ProcessBuilder.Redirect.INHERIT); | |||||
| builder.redirectError(ProcessBuilder.Redirect.INHERIT); | |||||
| process = builder.start(); | |||||
| try (BufferedReader linesReader = new BufferedReader( | |||||
| new InputStreamReader(process.getInputStream()))) { | |||||
| Assert.assertEquals( | |||||
| "Checking that bindServices=true results in image with provider.", | |||||
| 5, linesReader.lines().count()); | |||||
| } | |||||
| process.waitFor(); | |||||
| } | |||||
| private String runJlink(final String... args) { | |||||
| ToolProvider jlink = ToolProvider.findFirst("jlink").orElseThrow( | |||||
| () -> new RuntimeException("jlink tool not found in JDK.")); | |||||
| ByteArrayOutputStream stdout = new ByteArrayOutputStream(); | |||||
| ByteArrayOutputStream stderr = new ByteArrayOutputStream(); | |||||
| int exitCode; | |||||
| try (PrintStream out = new PrintStream(stdout); | |||||
| PrintStream err = new PrintStream(stderr)) { | |||||
| exitCode = jlink.run(out, err, args); | |||||
| } | |||||
| if (exitCode != 0) { | |||||
| throw new RuntimeException( | |||||
| "jlink failed, output is: " + stdout + ", error is: " + stderr); | |||||
| } | |||||
| return stdout.toString(); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,115 @@ | |||||
| package org.apache.tools.ant.types; | |||||
| import org.junit.Assert; | |||||
| import org.junit.Rule; | |||||
| import org.junit.Test; | |||||
| import org.junit.rules.ExpectedException; | |||||
| /** | |||||
| * Tests {@link ModuleVersion} class. | |||||
| */ | |||||
| public class ModuleVersionTest { | |||||
| @Rule | |||||
| public final ExpectedException expected = ExpectedException.none(); | |||||
| @Test | |||||
| public void testModuleVersionStringNumberPreBuild() { | |||||
| ModuleVersion moduleVersion = new ModuleVersion(); | |||||
| moduleVersion.setNumber("1.1.3"); | |||||
| moduleVersion.setPreRelease("ea"); | |||||
| moduleVersion.setBuild("25"); | |||||
| String versionStr = moduleVersion.toModuleVersionString(); | |||||
| Assert.assertNotNull("Checking for non-null module version string.", | |||||
| versionStr); | |||||
| Assert.assertTrue("Checking for correct module version string.", | |||||
| versionStr.matches("1\\.1\\.3[-+]ea\\+25")); | |||||
| } | |||||
| @Test | |||||
| public void testModuleVersionStringNumberPre() { | |||||
| ModuleVersion moduleVersion = new ModuleVersion(); | |||||
| moduleVersion.setNumber("1.1.3"); | |||||
| moduleVersion.setPreRelease("ea"); | |||||
| String versionStr = moduleVersion.toModuleVersionString(); | |||||
| Assert.assertNotNull("Checking for non-null module version string.", | |||||
| versionStr); | |||||
| Assert.assertTrue("Checking for correct module version string.", | |||||
| versionStr.matches("1\\.1\\.3[-+]ea")); | |||||
| } | |||||
| @Test | |||||
| public void testModuleVersionStringNumberBuild() { | |||||
| ModuleVersion moduleVersion = new ModuleVersion(); | |||||
| moduleVersion.setNumber("1.1.3"); | |||||
| moduleVersion.setBuild("25"); | |||||
| String versionStr = moduleVersion.toModuleVersionString(); | |||||
| Assert.assertNotNull("Checking for non-null module version string.", | |||||
| versionStr); | |||||
| Assert.assertTrue("Checking for correct module version string.", | |||||
| versionStr.matches("1\\.1\\.3[-+]\\+25")); | |||||
| } | |||||
| @Test | |||||
| public void testModuleVersionStringNumberOnly() { | |||||
| ModuleVersion moduleVersion = new ModuleVersion(); | |||||
| moduleVersion.setNumber("1.1.3"); | |||||
| String versionStr = moduleVersion.toModuleVersionString(); | |||||
| Assert.assertNotNull("Checking for non-null module version string.", | |||||
| versionStr); | |||||
| Assert.assertEquals("Checking for correct module version string.", | |||||
| "1.1.3", versionStr); | |||||
| } | |||||
| @Test | |||||
| public void testModuleVersionStringNullNumber() { | |||||
| expected.expect(IllegalStateException.class); | |||||
| ModuleVersion moduleVersion = new ModuleVersion(); | |||||
| moduleVersion.toModuleVersionString(); | |||||
| } | |||||
| @Test | |||||
| public void testNullNumber() { | |||||
| expected.expect(NullPointerException.class); | |||||
| ModuleVersion moduleVersion = new ModuleVersion(); | |||||
| moduleVersion.setNumber(null); | |||||
| } | |||||
| @Test | |||||
| public void testInvalidNumber() { | |||||
| expected.expect(IllegalArgumentException.class); | |||||
| ModuleVersion moduleVersion = new ModuleVersion(); | |||||
| moduleVersion.setNumber("1-1-3"); | |||||
| } | |||||
| @Test | |||||
| public void testInvalidNumber2() { | |||||
| expected.expect(IllegalArgumentException.class); | |||||
| ModuleVersion moduleVersion = new ModuleVersion(); | |||||
| moduleVersion.setNumber("1.1+3"); | |||||
| } | |||||
| @Test | |||||
| public void testInvalidPreRelease() { | |||||
| expected.expect(IllegalArgumentException.class); | |||||
| ModuleVersion moduleVersion = new ModuleVersion(); | |||||
| moduleVersion.setNumber("1.1.3"); | |||||
| moduleVersion.setPreRelease("ea+interim"); | |||||
| } | |||||
| } | |||||