diff options
author | Gintas Grigelionis <gintas@apache.org> | 2018-02-28 07:58:59 +0100 |
---|---|---|
committer | Gintas Grigelionis <gintas@apache.org> | 2018-02-28 08:00:45 +0100 |
commit | 66b52f99e4306fe928aa5e497021cb51cb927e5e (patch) | |
tree | c58d724bc70f01dcf464dc4c84832507ca8c4d82 /manual/tutorial-tasks-filesets-properties.html | |
parent | 3e61185e19eca3ca70afeda3fb31a1a544f2b474 (diff) | |
download | ant-66b52f99e4306fe928aa5e497021cb51cb927e5e.tar.gz |
Use HTML 5(-ish), fix links
Diffstat (limited to 'manual/tutorial-tasks-filesets-properties.html')
-rw-r--r-- | manual/tutorial-tasks-filesets-properties.html | 891 |
1 files changed, 394 insertions, 497 deletions
diff --git a/manual/tutorial-tasks-filesets-properties.html b/manual/tutorial-tasks-filesets-properties.html index 1662fcff6..01ec33406 100644 --- a/manual/tutorial-tasks-filesets-properties.html +++ b/manual/tutorial-tasks-filesets-properties.html @@ -22,9 +22,9 @@ <body> <h1>Tutorial: Tasks using Properties, Filesets & Paths</h1> -<p>After reading the tutorial about <a href="tutorial-writing-tasks.html">writing -tasks [1]</a> this tutorial explains how to get and set properties and how to use -nested filesets and paths. Finally it explains how to contribute tasks to Apache Ant.</p> +<p>After reading the tutorial about <a href="tutorial-writing-tasks.html">writing tasks [1]</a> this tutorial explains +how to get and set properties and how to use nested filesets and paths. Finally it explains how to contribute tasks to +Apache Ant.</p> <h2>Content</h2> <ul> @@ -40,14 +40,14 @@ nested filesets and paths. Finally it explains how to contribute tasks to Apache </ul> <h2 id="goal">The goal</h2> -<p>The goal is to write a task, which searchs in a path for a file and saves the -location of that file in a property.</p> +<p>The goal is to write a task, which searches in a path for a file and saves the location of that file in a +property.</p> <h2 id="buildenvironment">Build environment</h2> -<p>We can use the buildfile from the other tutorial and modify it a little bit. -That's the advantage of using properties - we can reuse nearly the whole script. :-)</p> +<p>We can use the buildfile from the other tutorial and modify it a little bit. That's the advantage of using +properties—we can reuse nearly the whole script. :-)</p> <pre class="code"> -<?xml version="1.0" encoding="ISO-8859-1"?> +<?xml version="1.0" encoding="UTF-8"?> <project name="<b>FindTask</b>" basedir="." default="test"> ... <target name="use.init" description="Taskdef's the <b>Find</b>-Task" depends="jar"> @@ -56,28 +56,26 @@ That's the advantage of using properties - we can reuse nearly the whole script. <b><!-- the other use.* targets are deleted --></b> ... -</project> -</pre> +</project></pre> -<p>The buildfile is in the archive <a href="tutorial-tasks-filesets-properties.zip"> -tutorial-tasks-filesets-properties.zip [2]</a> in <tt>/build.xml.01-propertyaccess</tt> -(future version saved as *.02..., final version as build.xml; same for sources).</p> +<p>The buildfile is in the +archive <a href="tutorial-tasks-filesets-properties.zip">tutorial-tasks-filesets-properties.zip [2]</a> +in <samp>/build.xml.01-propertyaccess</samp> (future version saved as *.02..., final version as <samp>build.xml</samp>; +same for sources).</p> <h2 id="propertyaccess">Property access</h2> -<p>Our first step is to set a property to a value and print the value of that property. - So our scenario would be</p> +<p>Our first step is to set a property to a value and print the value of that property. So +our scenario would be</p> <pre class="code"> <find property="test" value="test-value"/> - <find print="test"/> -</pre> -ok, can be rewritten with the core tasks + <find print="test"/></pre> +<p>Ok, it can be rewritten with the core tasks</p> <pre class="code"> <property name="test" value="test-value"/> - <echo message="${test}"/> -</pre> + <echo message="${test}"/></pre> <p>but I have to start on known ground :-)</p> -<p>So what to do? Handling three attributes (property, value, print) and an execute method. - Because this is only an introduction example I don't do much checking:</p> +<p>So what to do? Handling three attributes (<var>property</var>, <var>value</var>, <var>print</var>) and an execute +method. Because this is only an introduction example I don't do much checking:</p> <pre class="code"> import org.apache.tools.ant.BuildException; @@ -104,47 +102,39 @@ public class Find extends Task { <b>getProject().setNewProperty(property, value)</b>; } } -} -</pre> +}</pre> + +<p>As said in the other tutorial, the property access is done via Project instance. We get this instance via the +public <code>getProject()</code> method which we inherit from <code>Task</code> (more precisely +from <code>ProjectComponent</code>). Reading a property is done via <code>getProperty(<i>propertyname</i>)</code> (very +simple, isn't it?). This property returns the value as <samp>String</samp> or <code>null</code> if not set.<br/> +Setting a property is ... not really difficult, but there is more than one setter. You can use +the <code>setProperty()</code> method which will do the job as expected. But there is a golden rule in +Ant: <em>properties are immutable</em>. And this method sets the property to the specified value—whether it has a +value before that or not. So we use another way. <code>setNewProperty()</code> sets the property only if there is no +property with that name. Otherwise a message is logged.</p> -<p>As said in the other tutorial, the property access is done via Project instance. -We get this instance via the public <tt>getProject()</tt> method which we inherit from -<tt>Task</tt> (more precise from ProjectComponent). Reading a property is done via -<tt>getProperty(<i>propertyname</i>)</tt> (very simple, isn't it?). This property returns -the value as String or <i>null</i> if not set.<br> -Setting a property is ... not really difficult, but there is more than one setter. You can -use the <tt>setProperty()</tt> method which will do the job like expected. But there is -a golden rule in Ant: <i>properties are immutable</i>. And this method sets the property -to the specified value - whether it has a value before that or not. So we use another -way. <tt>setNewProperty()</tt> sets the property only if there is no property with that -name. Otherwise a message is logged.</p> - -<p><i>(by the way: a short word to ants "namespaces" (don't -be confused with xml namespaces: -an <code><antcall></code> creates a new space for property names. All properties from the caller -are passed to the callee, but the callee can set its own properties without notice by the -caller.)</i></p> - -<p>There are some other setter, too (but I haven't used them, so I can't say something -to them, sorry :-)</p> - -<p>After putting our two line example from above into a target names <tt>use.simple</tt> - we can call that from our testcase:</p> +<p><em>(by the way: a short word to Ant's "namespaces" (not to be confused with XML namespaces: +an <code><antcall></code> creates a new space for property names. All properties from the caller are passed to the +callee, but the callee can set its own properties without notice by the caller.)</em></p> + +<p>There are some other setters, too (but I haven't used them, so I can't say something to them, sorry :-)</p> + +<p>After putting our two line example from above into a target names <code>use.simple</code> we can call that from our +test case:</p> <pre class="code"> +import org.junit.Assert; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.junit.Before; -import org.junit.Assert; import org.apache.tools.ant.BuildFileRule; - public class FindTest { @Rule public final BuildFileRule buildRule = new BuildFileRule(); - @Before public void setUp() { configureProject("build.xml"); @@ -152,35 +142,32 @@ public class FindTest { @Test public void testSimple() { - buildRule.executeTarget("useSimgle"); + buildRule.executeTarget("useSimple"); <b>Assert.assertEquals("test-value", buildRule.getLog());</b> } -} -</pre> +}</pre> <p>and all works fine.</p> <h2 id="filesets">Using filesets</h2> -<p>Ant provides a common way of bundling files: the fileset. Because you are reading -this tutorial I think you know them and I don't have to spend more explanations about -their usage in buildfiles. Our goal is to search a file in path. And on this step the -path is simply a fileset (or more precise: a collection of filesets). So our usage -would be</p> +<p>Ant provides a common way of bundling files: the fileset. Because you are reading this tutorial I think you know them +and I don't have to spend more explanations about their usage in buildfiles. Our goal is to search for a file in +path. And in this step the path is simply a fileset (or more precise: a collection of filesets). So our usage would +be</p> <pre class="code"> <find file="ant.jar" location="location.ant-jar"> <fileset dir="${ant.home}" includes="**/*.jar"/> - </find> -</pre> + </find></pre> -<p>What do we need? A task with two attributes (file, location) and nested -filesets. Because we had attribute handling already explained in the example above and the - handling of nested elements is described in the other tutorial the code should be very easy:</p> +<p>What do we need? A task with two attributes (<var>file</var>, <var>location</var>) and nested filesets. Because we +had attribute handling already explained in the example above and the handling of nested elements is described in the +other tutorial, the code should be very easy:</p> <pre class="code"> public class Find extends Task { private String file; private String location; - private Vector filesets = new Vector(); + private List<FileSet> filesets = new ArrayList<>(); public void setFile(String file) { this.file = file; @@ -196,22 +183,21 @@ public class Find extends Task { public void execute() { } -} -</pre> -<p>Ok - that task wouldn't do very much, but we can use it in the described manner without -failure. On next step we have to implement the execute method. And before that we will -implement the appropriate testcases (TDD - test driven development).</p> - -<p>In the other tutorial we have reused the already written targets of our buildfile. -Now we will configure most of the testcases via java code (sometimes it's much easier - to write a target than doing it via java coding). What can be tested?</p> +}</pre> +<p>Ok—that task wouldn't do very much, but we can use it in the described manner without failure. In the next step +we have to implement the execute method. And before that we will implement the appropriate test cases (TDD—test +driven development).</p> + +<p>In the other tutorial we have reused the already written targets of our buildfile. Now we will configure most of the +test cases via Java code (sometimes it's much easier to write a target than doing it via Java coding). What can be +tested?</p> <ul> -<li>not valid configured task (missing file, missing location, missing fileset)</li> +<li>invalid configuration of the task (missing file, missing location, missing fileset)</li> <li>don't find a present file</li> <li>behaviour if file can't be found</li> </ul> -<p>Maybe you find some more testcases. But this is enough for now.<br> -For each of these points we create a <tt>testXX</tt> method.</p> +<p>Maybe you find some more test cases. But this is enough for now.<br/> +For each of these points we create a <code>testXX</code> method.</p> <pre class="code"> public class FindTest { @@ -219,44 +205,35 @@ public class FindTest { @Rule public final BuildFileRule buildRule = new BuildFileRule(); + @Rule + public ExpectedException tried = ExpectedException.none(); + ... // constructor, setUp as above @Test public void testMissingFile() { + tried.expect(BuildException.class); + tried.expectMessage("file not set"); <b>Find find = new Find();</b> - try { - <b>find.execute();</b> - fail("No 'no-file'-exception thrown."); - } catch (Exception e) { - // exception expected - String expected = "file not set"; - assertEquals("Wrong exception message.", expected, e.getMessage()); - } + <b>find.execute();</b> } @Test public void testMissingLocation() { + tried.expect(BuildException.class); + tried.expectMessage("location not set"); Find find = new Find(); <b>find.setFile("ant.jar");</b> - try { - find.execute(); - fail("No 'no-location'-exception thrown."); - } catch (Exception e) { - ... // similar to testMissingFile() - } + find.execute(); } @Test public void testMissingFileset() { + tried.expect(BuildException.class); + tried.expectMessage("fileset not set"); Find find = new Find(); find.setFile("ant.jar"); find.setLocation("location.ant-jar"); - try { - find.execute(); - fail("No 'no-fileset'-exception thrown."); - } catch (Exception e) { - ... // similar to testMissingFile() - } } @Test @@ -273,64 +250,58 @@ public class FindTest { assertNotNull("Property not set.", result); assertTrue("Wrong file found.", result.endsWith("ant.jar")); } -} -</pre> +}</pre> -<p>If we run this test class all test cases (except <i>testFileNotPresent</i>) fail. Now we -can implement our task, so that these test cases will pass.</p> +<p>If we run this test class all test cases (except <var>testFileNotPresent</var>) fail. Now we can implement our task, +so that these test cases will pass.</p> <pre class="code"> protected void validate() { - if (file==null) throw new BuildException("file not set"); - if (location==null) throw new BuildException("location not set"); - if (filesets.size()<1) throw new BuildException("fileset not set"); + if (file == null) throw new BuildException("file not set"); + if (location == null) throw new BuildException("location not set"); + if (filesets.size() < 1) throw new BuildException("fileset not set"); } public void execute() { validate(); // 1 String foundLocation = null; - for(Iterator itFSets = filesets.iterator(); itFSets.hasNext(); ) { // 2 - FileSet fs = (FileSet)itFSets.next(); + for (FileSet fs : filesets) { // 2 DirectoryScanner ds = fs.getDirectoryScanner(getProject()); // 3 - String[] includedFiles = ds.getIncludedFiles(); - for(int i=0; i<includedFiles.length; i++) { - String filename = includedFiles[i].replace('\\','/'); // 4 - filename = filename.substring(filename.lastIndexOf("/")+1); - if (foundLocation==null && file.equals(filename)) { + for (String includedFile : ds.getIncludedFiles()) { + String filename = includedFile.replace('\\','/'); // 4 + filename = filename.substring(filename.lastIndexOf("/") + 1); + if (foundLocation == null && file.equals(filename)) { File base = ds.getBasedir(); // 5 - File found = new File(base, includedFiles[i]); + File found = new File(base, includedFile); foundLocation = found.getAbsolutePath(); } } } - if (foundLocation!=null) // 6 + if (foundLocation != null) // 6 getProject().setNewProperty(location, foundLocation); - } -</pre> - -<p>On <b>//1</b> we check the prerequisites for our task. Doing that in a <tt>validate</tt>-method -is a common way, because we separate the prerequisites from the real work. On <b>//2</b> we iterate -over all nested filesets. If we don't want to handle multiple filesets, the <tt>addFileset()</tt> -method has to reject the further calls. We can get the result of a fileset via its DirectoryScanner -like done in <b>//3</b>. After that we create a platform independent String representation of -the file path (<b>//4</b>, can be done in other ways of course). We have to do the <tt>replace()</tt>, -because we work with a simple string comparison. Ant itself is platform independent and can -therefore run on filesystems with slash (/, e.g. Linux) or backslash (\, e.g. Windows) as -path separator. Therefore we have to unify that. If we found our file we create an absolute -path representation on <b>//5</b>, so that we can use that information without knowing the basedir. -(This is very important on use with multiple filesets, because they can have different basedirs -and the return value of the directory scanner is relative to its basedir.) Finally we store the -location of the file as property, if we had found one (<b>//6</b>).</p> - -<p>Ok, much more easier in this simple case would be to add the <i>file</i> as additional -<i>include</i> element to all filesets. But I wanted to show how to handle complex situations -without being complex :-)</p> - -<p>The test case uses the ant property <i>ant.home</i> as reference. This property is set by the -<tt>Launcher</tt> class which starts ant. We can use that property in our buildfiles as a -<a href="properties.html#built-in-props">build-in property [3]</a>. But if we create a new ant -environment we have to set that value for our own. And we use the <code><junit></code> task in fork-mode. -Therefore we have do modify our buildfile: + }</pre> + +<p>On <strong>//1</strong> we check the prerequisites for our task. Doing that in a <code>validate</code>-method is a +common way, because we separate the prerequisites from the real work. On <strong>//2</strong> we iterate over all nested +filesets. If we don't want to handle multiple filesets, the <code>addFileset()</code> method has to reject the further +calls. We can get the result of a fileset via its DirectoryScanner like done in <strong>//3</strong>. After that we +create a platform independent String representation of the file path (<strong>//4</strong>, can be done in other ways of +course). We have to do the <code>replace()</code>, because we work with a simple string comparison. Ant itself is +platform independent and can therefore run on filesystems with slash (<q>/</q>, e.g. Linux) or backslash (<q>\</q>, +e.g. Windows) as path separator. Therefore we have to unify that. If we find our file, we create an absolute path +representation on <strong>//5</strong>, so that we can use that information without knowing the <var>basedir</var>. +(This is very important on use with multiple filesets, because they can have different <var>basedir</var>s and the +return value of the directory scanner is relative to its <var>basedir</var>.) Finally we store the location of the file +as property, if we had found one (<strong>//6</strong>).</p> + +<p>Ok, much more easier in this simple case would be to add the <var>file</var> as additional <code>include</code> +element to all filesets. But I wanted to show how to handle complex situations without being complex :-)</p> + +<p>The test case uses the Ant property <code>ant.home</code> as reference. This property is set by +the <code>Launcher</code> class which starts ant. We can use that property in our buildfiles as +a <a href="properties.html#built-in-props">build-in property [3]</a>. But if we create a new Ant environment we have to +set that value for our own. And we use the <code><junit></code> task in <var>fork</var> mode. Therefore we have +do modify our buildfile:</p> <pre class="code"> <target name="junit" description="Runs the unit tests" depends="jar"> <delete dir="${junit.out.dir.xml}"/> @@ -343,99 +314,95 @@ Therefore we have do modify our buildfile: <fileset dir="${src.dir}" includes="**/*Test.java"/> </batchtest> </junit> - </target> -</pre> + </target></pre> <h2 id="path">Using nested paths</h2> -<p>A task providing support for filesets is a very comfortable one. But there is another -possibility of bundling files: the <code><path></code>. Fileset are easy if the files are all under -a common base directory. But if this is not the case you have a problem. Another disadvantage -is its speed: if you have only a few files in a huge directory structure, why not use a -<code><filelist></code> instead? <code><path></code>s combines these datatypes in that way that a path contains -other paths, filesets, dirsets and filelists. This is why <a href="http://ant-contrib.sourceforge.net/"> -Ant-Contribs [4]</a> <code><foreach></code> task is modified to support paths instead of filesets. So we want that, -too.</p> +<p>A task providing support for filesets is a very comfortable one. But there is another possibility of bundling files: +the <code><path></code>. Filesets are easy if the files are all under a common base directory. But if this is not +the case, you have a problem. Another disadvantage is its speed: if you have only a few files in a huge directory +structure, why not use a <code><filelist></code> instead? <code><path></code>s combines these datatypes in +that way that a path contains other paths, filesets, dirsets and filelists. This is +why <a href="http://ant-contrib.sourceforge.net/">Ant-Contrib [4]</a> <code><foreach></code> task is modified to +support paths instead of filesets. So we want that, too.</p> <p>Changing from fileset to path support is very easy:</p> +<em><strong>Change Java code from:</strong></em> <pre class="code"> -<i><b>Change java code from:</b></i> - private Vector filesets = new Vector(); + private List<FileSet> filesets = new ArrayList<>(); public void addFileset(FileSet fileset) { filesets.add(fileset); - } -<i><b>to:</b></i> - private Vector paths = new Vector(); *1 + }</pre> +<em><strong>to:</strong></em> +<pre class="code"> + private List<Path> paths = new ArrayList<>(); *1 public void add<b>Path</b>(<b>Path</b> path) { *2 paths.add(path); - } -<i><b>and build file from:</b></i> + }</pre> +<em><strong>and build file from:</strong></em> +<pre class="code"> <find file="ant.jar" location="location.ant-jar"> <fileset dir="${ant.home}" includes="**/*.jar"/> - </find> -<i><b>to:</b></i> + </find></pre> +<em><strong>to:</strong></em> +<pre class="code"> <find file="ant.jar" location="location.ant-jar"> <b><path></b> *3 <fileset dir="${ant.home}" includes="**/*.jar"/> </path> - </find> -</pre> -<p>On <b>*1</b> we rename only the vector. It�s just for better reading the source. On <b>*2</b> -we have to provide the right method: an add<i>Name</i>(<i>Type</i> t). Therefore replace the -fileset with path here. Finally we have to modify our buildfile on <b>*3</b> because our task -doesn�t support nested filesets any longer. So we wrap the fileset inside a path.</p> - -<p>And now we modify the testcase. Oh, not very much to do :-) Renaming the <tt>testMissingFileset()</tt> -(not really a <i>must-be</i> but better it�s named like the think it does) and update the -<i>expected</i>-String in that method (now a <tt>path not set</tt> message is expected). The more complex -test cases base on the buildscript. So the targets <tt>testFileNotPresent</tt> and <tt>testFilePresent</tt> have to be -modified in the manner described above.</p> - -<p>The test are finished. Now we have to adapt the task implementation. The easiest modification is -in the <tt>validate()</tt> method where we change le last line to <tt>if (paths.size()<1) throw new -BuildException("path not set");</tt>. In the <tt>execute()</tt> method we have a little more work. -... mmmh ... in reality it's lesser work, because the Path class does the whole DirectoryScanner-handling -and creating-absolute-paths stuff for us. So the execute method is just:</p> + </find></pre> +<p>On <strong>*1</strong> we rename only the list. It's just for better reading the source. On <strong>*2</strong> we +have to provide the right method: an <code>add<i>Name</i>(<i>Type</i> t)</code>. Therefore replace the fileset with path +here. Finally we have to modify our buildfile on <strong>*3</strong> because our task doesn't support nested filesets +any longer. So we wrap the fileset inside a path.</p> + +<p>And now we modify the test case. Oh, not very much to do :-) Renaming the <code>testMissingFileset()</code> (not +really a <em>must-be</em> but better it's named like the thing it does) and update the <var>expected</var>-String in +that method (now a <samp>path not set</samp> message is expected). The more complex test cases base on the build +script. So the targets <var>testFileNotPresent</var> and <var>testFilePresent</var> have to be modified in the manner +described above.</p> + +<p>The test are finished. Now we have to adapt the task implementation. The easiest modification is in +the <code>validate()</code> method where we change the last line to <code>if (paths.size()<1) throw new +BuildException("path not set");</code>. In the <code>execute()</code> method we have a little more work. ... mmmh +... in reality it's less work, because the Path class does the whole DirectoryScanner-handling and +creating-absolute-paths stuff for us. So the execute method becomes just:</p> <pre class="code"> public void execute() { validate(); String foundLocation = null; - for(Iterator itPaths = paths.iterator(); itPaths.hasNext(); ) { - Path path = (<b>Path</b>)itPaths.next(); // 1 - String[] includedFiles = <b>path.list()</b>; // 2 - for(int i=0; i<includedFiles.length; i++) { - String filename = includedFiles[i].replace('\\','/'); - filename = filename.substring(filename.lastIndexOf("/")+1); - if (foundLocation==null && file.equals(filename)) { - <b>foundLocation = includedFiles[i];</b> // 3 + for (Path path : paths) { // 1 + for (String includedFile : <b>path.list()</b>) { // 2 + String filename = includedFile.replace('\\','/'); + filename = filename.substring(filename.lastIndexOf("/") + 1); + if (foundLocation == null && file.equals(filename)) { + <b>foundLocation = includedFile;</b> // 3 } } } - if (foundLocation!=null) + if (foundLocation != null) getProject().setNewProperty(location, foundLocation); } </pre> -<p>Of course we have to do the typecase to Path on <b>//1</b>. On <b>//2</b> and <b>//3</b> -we see that the Path class does the work for us: no DirectoryScanner (was at 2) and no -creating of the absolute path (was at 3).</p> +<p>Of course we have to iterate through paths on <strong>//1</strong>. On <strong>//2</strong> and <strong>//3</strong> +we see that the Path class does the work for us: no DirectoryScanner (was at 2) and no creating of the absolute path +(was at 3).</p> <h2 id="returning-list">Returning a list</h2> -<p>So far so good. But could a file be on more than one place in the path? - Of course.<br> -And would it be good to get all of them? - It depends on ...<p> +<p>So far so good. But could a file be on more than one place in the path?—Of course.<br/> +And would it be good to get all of them?—It depends ...<p> -<p>In this section we will extend that task to support returning a list of all files. -Lists as property values are not supported by Ant natively. So we have to see how other -tasks use lists. The most famous task using lists is Ant-Contribs <code><foreach></code>. All list -elements are concatenated and separated with a customizable separator (default ',').</p> +<p>In this section we will extend that task to support returning a list of all files. Lists as property values are not +supported by Ant natively. So we have to see how other tasks use lists. The most famous task using lists is +Ant-Contribs <code><foreach></code>. All list elements are concatenated and separated with a customizable +separator (default <q>,</q>).</p> <p>So we do the following:</p> -<pre class="code"> - <find ... <b>delimiter=""</b>/> ... </find> -</pre> +<pre class="code"><find ... <b>delimiter=""</b>/> ... </find></pre> -<p>If the delimiter is set we will return all found files as list with that delimiter.</p> +<p>if the delimiter is set, we will return all found files as list with that delimiter.</p> <p>Therefore we have to</p> <ul> @@ -446,9 +413,9 @@ elements are concatenated and separated with a customizable separator (default ' <li>return that list</li> </ul> -<p>So we add as testcase:</p> +<p>So we add as test case:</p> +<strong><em>in the buildfile:</em></strong> <pre class="code"> -<b><i>in the buildfile:</i></b> <target name="test.init"> <mkdir dir="test1/dir11/dir111"/> *1 <mkdir dir="test1/dir11/dir112"/> @@ -477,27 +444,25 @@ elements are concatenated and separated with a customizable separator (default ' <fileset dir="test1"/> <fileset dir="test2"/> </delete> - </target> - -<b><i>in the test class:</i></b> + </target></pre> +<strong><em>in the test class:</em></strong> +<pre class="code"> public void testMultipleFiles() { executeTarget("testMultipleFiles"); String result = getProject().getProperty("location.test"); assertNotNull("Property not set.", result); assertTrue("Only one file found.", result.indexOf(";") > -1); - } -</pre> + }</pre> -<p>Now we need a directory structure where we CAN find files with the same -name in different directories. Because we can't sure to have one we create -one on <b>*1</b> and <b>*2</b>. And of course we clean up that on <b>*4</b>. The creation -can be done inside our test target or in a separate one, which will be better -for reuse later (<b>*3</b>). +<p>Now we need a directory structure where we CAN find files with the same name in different directories. Because we +can't sure to have one we create one on <strong>*1</strong> and <strong>*2</strong>. And of course we clean up that +on <strong>*4</strong>. The creation can be done inside our test target or in a separate one, which will be better for +reuse later (<strong>*3</strong>). <p>The task implementation is modified as followed:</p> <pre class="code"> - private Vector foundFiles = new Vector(); + private List<String> foundFiles = new ArrayList<>(); ... private String delimiter = null; ... @@ -508,70 +473,63 @@ for reuse later (<b>*3</b>). public void execute() { validate(); // find all files - for(Iterator itPaths = paths.iterator(); itPaths.hasNext(); ) { - Path path = (Path)itPaths.next(); - String[] includedFiles = path.list(); - for(int i=0; i<includedFiles.length; i++) { - String filename = includedFiles[i].replace('\\','/'); + for (Path path : paths) { + for (File includedFile : path.list()) { + String filename = includedFile.replace('\\','/'); filename = filename.substring(filename.lastIndexOf("/")+1); - if (file.equals(filename) && <b>!foundFiles.contains(includedFiles[i]</b>)) { // 1 - foundFiles.add(includedFiles[i]); + if (file.equals(filename) && <b>!foundFiles.contains(includedFile)</b>) { // 1 + foundFiles.add(includedFile); } } } // create the return value (list/single) String rv = null; - if (foundFiles.size() > 0) { // 2 - if (delimiter==null) { + if (!foundFiles.isEmpty()) { // 2 + if (delimiter == null) { // only the first - rv = (String)foundFiles.elementAt(0); + rv = foundFiles.get(0); } else { // create list - StringBuffer list = new StringBuffer(); - for(Iterator it=foundFiles.iterator(); it.hasNext(); ) { // 3 + StringBuilder list = new StringBuilder(); + for (String file : foundFiles) { // 3 list.append(it.next()); - if (<b>it.hasNext()</b>) list.append(delimiter); // 4 - } + if (<b>list.length() > 0</b>) list.append(delimiter); // 4 + } rv = list.toString(); } } // create the property - if (rv!=null) + if (rv != null) getProject().setNewProperty(location, rv); - } -</pre> + }</pre> -<p>The algorithm does: finding all files, creating the return value depending on the users -wish, returning the value as property. On <b>//1</b> we eliminates the duplicates. <b>//2</b> -ensures that we create the return value only if we have found one file. On <b>//3</b> we -iterate over all found files and <b>//4</b> ensures that the last entry has no trailing -delimiter.</p> +<p>The algorithm does: finding all files, creating the return value depending on the users wish, returning the value as +property. On <strong>//1</strong> we eliminates the duplicates. <strong>//2</strong> ensures that we create the return +value only if we have found one file. On <strong>//3</strong> we iterate over all found files and <strong>//4</strong> +ensures that the last entry has no trailing delimiter.</p> -<p>Ok, first searching for all files and then returning only the first one ... You can -tune the performance of your own :-)</p> +<p>Ok, first searching for all files and then returning only the first one ... You can tune the performance of your own +:-)</p> <h2 id="documentation">Documentation</h2> -<p>A task is useless if the only who is able to code the buildfile is the task developer -(and he only the next few weeks :-). So documentation is also very important. In which -form you do that depends on your favourite. But inside Ant there is a common format and -it has advantages if you use that: all task users know that form, this form is requested if -you decide to contribute your task. So we will doc our task in that form.</p> - -<p>If you have a look at the manual page of the <a href="Tasks/java.html">Java task [5]</a> - you will see that it:<ul> +<p>A task is useless if the only who is able to code the buildfile is the task developer (and he only the next few weeks +:-). So documentation is also very important. In which form you do that depends on your favourite. But inside Ant there +is a common format and it has advantages if you use that: all task users know that form, this form is requested if you +decide to contribute your task. So we will doc our task in that form.</p> + +<p>If you have a look at the manual page of the <a href="Tasks/java.html">Java task [5]</a> you will see that it:</p> +<ul> <li>is plain html</li> <li>starts with the name</li> -<li>has sections: description, parameters, nested elements, (maybe return codes) and (most -important :-) examples</li> -<li>parameters are listed in a table with columns for attribute name, its description and whether - it's required (if you add a feature after an Ant release, provide a <tt>since Ant xx</tt> - statement when it's introduced)</li> +<li>has sections: description, parameters, nested elements, (maybe return codes) and (most important :-) examples</li> +<li>parameters are listed in a table with columns for attribute name, its description and whether it's required (if you +add a feature after an Ant release, provide a <em>since Ant xx</em> statement when it's introduced)</li> <li>describe the nested elements (since-statement if necessary)</li> <li>provide one or more useful examples; first code, then description.</li> </ul> -As a template we have: +<p>As a template we have:</p> <pre class="code"> <html> @@ -583,23 +541,23 @@ As a template we have: <body> -<h2& id="<b>taskname</b>"><b>Taskname</b></h2> +<h2 id="<b>taskname</b>"><b>Taskname</b></h2> <h3>Description</h3> -<p> <b>Describe the task.</b></p> +<p><b>Describe the task.</b></p> <h3>Parameters</h3> -<table> +<table class="attr"> <tr> - <td valign="top"><b>Attribute</b></td> - <td valign="top"><b>Description</b></td> - <td align="center" valign="top"><b>Required</b></td> + <th>Attribute</th> + <th>Description</th> + <th>Required</th> </tr> <b>do this html row for each attribute (including inherited attributes)</b> <tr> - <td valign="top">classname</td> - <td valign="top">the Java class to execute.</td> - <td align="center" valign="top">Either jar or classname</td> + <td>classname</td> + <td>the Java class to execute.</td> + <td>Either jar or classname</td> </tr> </table> @@ -618,8 +576,7 @@ As a template we have: <b>What should that example do?</b> </body> -</html> -</pre> +</html></pre> <p>Here is an example documentation page for our task:</p> <pre class="code"> @@ -634,30 +591,30 @@ As a template we have: <h2 id="find">Find</h2> <h3>Description</h3> -<p>Searchs in a given path for a file and returns the absolute to it as property. +<p>Searches in a given path for a file and returns the absolute to it as property. If delimiter is set this task returns all found locations.</p> <h3>Parameters</h3> -<table> +<table class="attr"> <tr> - <td valign="top"><b>Attribute</b></td> - <td valign="top"><b>Description</b></td> - <td align="center" valign="top"><b>Required</b></td> + <th>Attribute</th> + <th>Description</th> + <th>Required</th> </tr> <tr> - <td valign="top">file</td> - <td valign="top">The name of the file to search.</td> - <td align="center" valign="top">yes</td> + <td>file</td> + <td>The name of the file to search.</td> + <td>yes</td> </tr> <tr> - <td valign="top">location</td> - <td valign="top">The name of the property where to store the location</td> - <td align="center" valign="top">yes</td> + <td>location</td> + <td>The name of the property where to store the location</td> + <td>yes</td> </tr> <tr> - <td valign="top">delimiter</td> - <td valign="top">A delimiter to use when returning the list</td> - <td align="center" valign="top">only if the list is required</td> + <td>delimiter</td> + <td>A delimiter to use when returning the list</td> + <td>only if the list is required</td> </tr> </table> @@ -668,284 +625,229 @@ If delimiter is set this task returns all found locations.</p> <h3>Examples</h3> <pre> - <find file="ant.jar" location="loc"> - <path> - <fileset dir="${ant.home}"/> - <path> - </find> -</pre> -Searches in Ants home directory for a file <i>ant.jar</i> and stores its location in -property <i>loc</i> (should be ANT_HOME/bin/ant.jar). +<find file="ant.jar" location="loc"> + <path> + <fileset dir="${ant.home}"/> + <path> +</find></pre> +Searches in Ant's home directory for a file <samp>ant.jar</samp> and stores its location in +property <code>loc</code> (should be <samp>ANT_HOME/bin/ant.jar</samp>). <pre> - <find file="ant.jar" location="loc" delimiter=";"> - <path> - <fileset dir="C:/"/> - <path> - </find> - <echo>ant.jar found in: ${loc}</echo> -</pre> -Searches in Windows C: drive for all <i>ant.jar</i> and stores their locations in -property <i>loc</i> delimited with <i>';'</i>. (should need a long time :-) -After that it prints out the result (e.g. C:/ant-1.5.4/bin/ant.jar;C:/ant-1.6/bin/ant.jar). +<find file="ant.jar" location="loc" delimiter=";"> + <path> + <fileset dir="C:/"/> + <path> +</find> +<echo>ant.jar found in: ${loc}</echo></pre> +Searches in Windows C: drive for all <samp>ant.jar</samp> and stores their locations in +property <code>loc</code> delimited with <q>;</q>. (should need a long time :-) +After that it prints out the result (e.g. <samp>C:/ant-1.5.4/bin/ant.jar;C:/ant-1.6/bin/ant.jar</samp>). </body> -</html> -</pre> +</html></pre> <h2 id="contribute">Contribute the new task</h2> -If we decide to contribute our task, we should do some things: +<p>If we decide to contribute our task, we should do some things:</p> <ul> <li>is our task welcome? :-) Simply ask on the user list</li> -<li>is the right package used? </li> +<li>is the right package used?</li> <li>does the code conform to the styleguide?</li> -<li>do all tests pass? </li> -<li>does the code compile on JDK 1.2 (and passes all tests there)?</li> +<li>do all tests pass?</li> +<li>does the code compile on JDK 5 (and passes all tests there)?</li> <li>code under Apache license</li> <li>create a patch file</li> <li>publishing that patch file</li> </ul> -<p>The <a href="http://ant.apache.org/ant_task_guidelines.html">Ant Task Guidelines [6]</a> support additional +<p>The <a href="https://ant.apache.org/ant_task_guidelines.html">Ant Task Guidelines [6]</a> support additional information on that.</p> -<p>Now we will check the "Checklist before submitting a new task" described in that guideline. +<p>Now we will check the "Checklist before submitting a new task" described in that guideline.</p> <ul> -<li>Java file begins with Apache license statement. <b><i>must do that</i></b></li> -<li>Task does not depend on GPL or LGPL code. <b><i>ok</i></b></li> -<li>Source code complies with style guidelines <b><i>have to check (checkstyle)</i></b></li> -<li>Code compiles and runs on Java1.2 <b><i>have to try</i></b></li> -<li>Member variables are private, and provide public accessor methods - if access is actually needed. <b><i>have to check (checkstyle)</i></b></li> -<li><i>Maybe</i> Task has failonerror attribute to control failure behaviour <b><i>hasn't</i></b></li> -<li>New test cases written and succeed <b><i>passed on JDK 1.4, have to try on JDK 1.2</i></b></li> -<li>Documentation page written <b><i>ok</i></b></li> -<li>Example task declarations in the documentation tested. <b><i>ok (used in tests)</i></b></li> -<li>Patch files generated using cvs diff -u <b><i>to do</i></b></li> -<li>patch files include a patch to defaults.properties to register the -tasks <b><i>to do</i></b></li> -<li>patch files include a patch to tasklist.html to link to the new task page <b><i>to do</i></b></li> -<li>Message to dev contains [SUBMIT] and task name in subject <b><i>to do</i></b></li> -<li>Message body contains a rationale for the task <b><i>to do</i></b></li> -<li>Message attachments contain the required files -source, documentation, -test and patches zipped up to escape the HTML filter. <b><i>to do</i></b></li> +<li>Java file begins with Apache license statement. <strong><em>must do that</em></strong></li> +<li>Task does not depend on GPL or LGPL code. <strong><em>ok</em></strong></li> +<li>Source code complies with style guidelines <strong><em>have to check (checkstyle)</em></strong></li> +<li>Code compiles and runs on Java 5 <strong><em>have to try</em></strong></li> +<li>Member variables are private, and provide public accessor methods if access is actually needed. <strong><em>have to +check (checkstyle)</em></strong></li> +<li><em>Maybe</em> Task has <var>failonerror</var> attribute to control failure +behaviour <strong><em>hasn't</em></strong></li> +<li>New test cases written and succeed <strong><em>passed on JDK 8, have to try on JDK 5</em></strong></li> +<li>Documentation page written <strong><em>ok</em></strong></li> +<li>Example task declarations in the documentation tested. <strong><em>ok (used in tests)</em></strong></li> +<li>Message to dev contains [SUBMIT] and task name in subject <strong><em>to do</em></strong></li> +<li>Message body contains a rationale for the task <strong><em>to do</em></strong></li> +<li>Message body contains the URL to GitHub pull request. <strong><em>to do</em></strong></li> </ul> <h3>Package / Directories</h3> -<p>This task does not depend on any external library. Therefore we can use this as -a core task. This task contains only one class. So we can use the standard package -for core tasks: <tt>org.apache.tools.ant.taskdefs</tt>. Implementations are in the -directory <tt>src/main</tt>, tests in <tt>src/testcases</tt> and buildfiles for -tests in <tt>src/etc/testcases</tt>.</p> - -<p>Now we integrate our work into Ants distribution. So first we do an update of our -cvs tree. If not done yet, you have to checkout the ant module from Apaches cvs server -as described in <a href="http://ant.apache.org/cvs.html">Access the Source Tree (AnonCVS) -[7]</a> (password is <i>anoncvs</i>):</p> -<pre class="output"> -cvs -d :pserver:anoncvs@cvs.apache.org:/home/cvspublic login //1 -cvs -d :pserver:anoncvs@cvs.apache.org:/home/cvspublic checkout ant //2 -</pre> -If you have a local copy of Ants sources just do an update -<pre class="output"> -cvs -d :pserver:anoncvs@cvs.apache.org:/home/cvspublic login -cd ant //3 -cvs -d :pserver:anoncvs@cvs.apache.org:/home/cvspublic update //4 -</pre> - -<p>We use the <i>-d</i> flag on <b>//1</b> to specify the cvs directory. You can -specify the environment variable CVSROOT with that value and after that you haven�t -to use that flag any more. On <b>//2</b> we get the whole cvs tree of ant. (Sorry, -but that uses a lot of time ... 10 up to 30 minutes are not unusual ... but this has -to be done only once :-). A cvs update doesn't use a modulename but you have to be -inside the directory. Therefore we go into that on <b>//3</b> and do the update -on <b>//4</b>.</p> - -<p>Now we will build our Ant distribution and do a test. So we can see if there -are any tests failing on our machine. (We can ignore these failing tests on later - steps; windows syntax used here- translate to xNIX if needed):</p> +<p>This task does not depend on any external library. Therefore we can use this as a core task. This task contains only +one class. So we can use the standard package for core +tasks: <code>org.apache.tools.ant.taskdefs</code>. Implementations are in the directory <samp>src/main</samp>, tests +in <samp>src/testcases</samp> and buildfiles for tests in <samp>src/etc/testcases</samp>.</p> + +<p>Now we integrate our work into Ant distribution. So first we do an update of our Git tree. If not done yet, you +should clone the Ant repository on GitHub[7], then create a local clone:</p> +<pre class="output">git clone https://github.com/<em>your-sig</em>/ant.git</pre> + +<p>Now we will build our Ant distribution and do a test. So we can see if there are any tests failing on our +machine. (We can ignore these failing tests on later steps; Windows syntax used here—translate to UNIX if +needed):</p> <pre class="output"> -ANTHOME> build // 1 -ANTHOME> set ANT_HOME=%CD%\dist // 2 -ANTHOME> ant test -Dtest.haltonfailure=false // 3 -</pre> +ANTREPO> build // 1 +ANTREPO> set ANT_HOME=%CD%\dist // 2 +ANTREPO> ant test -Dtest.haltonfailure=false // 3</pre> -<p>First we have to build our Ant distribution (<b>//1</b>). On <b>//2</b> we set the ANT_HOME -environment variable to the directory where the new created distribution is stored -(%CD% is expanded to the current directory on Windows 2000 and XP, on 9x and NT -write it out). On <b>//3</b> we let Ant do all the tests (which enforced a compile -of all tests) without stopping on first failure.</p> +<p>First we have to build our Ant distribution (<strong>//1</strong>). On <strong>//2</strong> we set +the <code>ANT_HOME</code> environment variable to the directory where the new created distribution is stored +(<code>%CD%</code> is expanded to the current directory on Windows 2000 and later). On <strong>//3</strong> we let Ant +do all the tests (which enforced a compile of all tests) without stopping on first failure.</p> -<p>Next we apply our work onto Ants sources. Because we haven't modified any, this is -a relative simple step. <i>(Because I have a local copy of Ant and usually contribute my -work, I work on the local copy just from the beginning. The advantage: this step isn't -necessary and saves a lot of work if you modify existing source :-)</i>. +<p>Next we apply our work onto Ant sources. Because we haven't modified any, this is a relatively simple +step. <em>(Because I have a local Git clone of Ant and usually contribute my work, I work on the local copy just from +the beginning. The advantage: this step isn't necessary and saves a lot of work if you modify existing sources :-)</em>. <ul> -<li>move the Find.java to ANTHOME/src/main/org/apache/tools/ant/taskdefs/Find.java </li> -<li>move the FindTest.java to ANTHOME/src/testcases/org/apache/tools/ant/taskdefs/FindTest.java </li> -<li>move the build.xml to ANTHOME/src/etc/testcases/taskdefs/<b>find.xml</b> (!!! renamed !!!)</li> -<li>add a <tt>package org.apache.tools.ant.taskdefs;</tt> at the beginning of the two java files </li> -<li>delete all stuff from find.xml keeping the targets "testFileNotPresent", "testFilePresent", - "test.init" and "testMultipleFiles" </li> -<li>delete the dependency to "use.init" in the find.xml </li> -<li>in FindTest.java change the line <tt>configureProject("build.xml");</tt> to - <tt>configureProject("src/etc/testcases/taskdefs/find.xml");</tt> </li> -<li>move the find.html to ANTHOME/docs/manual/Tasks/find.html </li> -<li>add a <tt><a href="Tasks/find.html">Find</a><br></tt> - in the ANTHOME/docs/manual/tasklist.html </li> + <li>move the <samp>Find.java</samp> to <samp>ANTREPO/src/main/org/apache/tools/ant/taskdefs/Find.java</samp></li> + <li>move the <samp>FindTest.java</samp> to <samp>ANTREPO/src/testcases/org/apache/tools/ant/taskdefs/FindTest.java</samp></li> + <li>move the <samp>build.xml</samp> to <samp>ANTREPO/src/etc/testcases/taskdefs/<strong>find.xml</strong></samp> (!!! renamed !!!)</li> + <li>add a <code>package org.apache.tools.ant.taskdefs;</code> at the beginning of the two java files</li> + <li>delete all stuff from <samp>find.xml</samp> keeping the + targets <q>testFileNotPresent</q>, <q>testFilePresent</q>, <q>test.init</q> and <q>testMultipleFiles</q></li> + <li>delete the dependency to <q>use.init</q> in the <samp>find.xml</samp></li> + <li>in <samp>FindTest.java</samp> change the line <code>configureProject("build.xml");</code> + to <code>configureProject("src/etc/testcases/taskdefs/find.xml");</code></li> + <li>move the <samp>find.html</samp> to <samp>ANTREPO/docs/manual/Tasks/find.html</samp></li> + <li>add a <code><a href="Tasks/find.html">Find</a><br></code> in + the <samp>ANTREPO/docs/manual/tasklist.html</samp></li> </ul> -Now our modifications are done and we will retest it: +<p>Now our modifications are done and we will retest it:</p> <pre class="output"> -ANTHOME> build -ANTHOME> ant run-single-test // 1 +ANTREPO> build +ANTREPO> ant run-single-test // 1 -Dtestcase=org.apache.tools.ant.taskdefs.FindTest // 2 - -Dtest.haltonfailure=false -</pre> -<p>Because we only want to test our new class, we use the target for single tests, specify -the test to use and configure not to halt on the first failure - we want to see all -failures of our own test (<b>//1 + 2</b>).</p> - -<p>And ... oh, all tests fail: <i>Ant could not find the task or a class this task relies upon.</i></p> - -<p>Ok: in the earlier steps we told Ant to use the Find class for the <code><find></code> task (remember the -<code><taskdef></code> statement in the "use.init" target). But now we want to introduce that task as -a core task. And nobody wants to taskdef the javac, echo, ... So what to do? The answer is the -src/main/.../taskdefs/default.properties. Here is the mapping between taskname and implementing -class done. So we add a <tt>find=org.apache.tools.ant.taskdefs.Find</tt> as the last core - task (just before the <tt># optional tasks</tt> line). Now a second try:</p> + -Dtest.haltonfailure=false</pre> +<p>Because we only want to test our new class, we use the target for single tests, specify the test to use and configure +not to halt on the first failure—we want to see all failures of our own test (<strong>//1 + 2</strong>).</p> + +<p>And ... oh, all tests fail: <em>Ant could not find the task or a class this task relies upon.</em></p> + +<p>Ok: in the earlier steps we told Ant to use the Find class for the <code><find></code> task (remember +the <code><taskdef></code> statement in the "use.init" target). But now we want to introduce that task as a core +task. And nobody wants to taskdef the javac, echo, ... So what to do? The answer is +the <samp>src/main/.../taskdefs/default.properties</samp>. Here is the mapping between taskname and implementing class +done. So we add a <code>find=org.apache.tools.ant.taskdefs.Find</code> as the last core task (just before the <code># +optional tasks</code> line). Now a second try:</p> <pre class="output"> -ANTHOME> build // 1 -ANTHOME> ant run-single-test +ANTREPO> build // 1 +ANTREPO> ant run-single-test -Dtestcase=org.apache.tools.ant.taskdefs.FindTest - -Dtest.haltonfailure=false -</pre> -We have to rebuild (<b>//1</b>) Ant because the test look in the %ANT_HOME%\lib\ant.jar -(more precise: on the classpath) for the properties file. And we have only modified it in the -source path. So we have to rebuild that jar. But now all tests pass and we check whether our class -breaks some other tests. -<pre class="output"> -ANTHOME> ant test -Dtest.haltonfailure=false -</pre> -<p>Because there are a lot of tests this step requires a little bit of time. So use the <i>run-single-test</i> -during development and do the <i>test</i> only at the end (maybe sometimes during development too). -We use the <i>-Dtest.haltonfailure=false</i> here because there could be other tests fail and we have -to look into them.</p> - -<p>This test run should show us two things: our test will run and the number of failing tests -is the same as directly after the cvs update (without our modifications).</p> + -Dtest.haltonfailure=false</pre> +<p>We have to rebuild (<strong>//1</strong>) Ant because the test look in the <samp>%ANT_HOME%\lib\ant.jar</samp> (more +precise: on the classpath) for the properties file. And we have only modified it in the source path. So we have to +rebuild that jar. But now all tests pass and we check whether our class breaks some other tests.</p> +<pre class="output">ANTREPO> ant test -Dtest.haltonfailure=false</pre> +<p>Because there are a lot of tests this step requires a little bit of time. So use the <q>run-single-test</q> during +development and do the <q>test</q> only at the end (maybe sometimes during development too). We use +the <code>-Dtest.haltonfailure=false</code> here because there could be other tests fail and we have to look into +them.</p> + +<p>This test run should show us two things: our test will run and the number of failing tests is the same as directly +after <code>git clone</code> (without our modifications).</p> <h3>Apache license statement</h3> <p>Simply copy the license text from one the other source from the Ant source tree.</p> -<h3>Test on JDK 1.2</h3> -<p>Until version 1.5 Ant must be able to run on a JDK 1.1. With version 1.6 this is not a -requisite any more. But JDK 1.2 is a must-to-work-with. So we have to test that. You can download older -JDKs from <a href="http://www.oracle.com/technetwork/java/archive-139210.html">Oracle [8]</a>.</p> +<h3>Test on JDK 5</h3> +<p>Ant 1.10 uses Java 8 for development, but Ant 1.9 is actively maintained, too. That means that Ant code must be able +to run on a JDK 5. So we have to test that. You can download older JDKs +from <a href="https://www.oracle.com/technetwork/java/archive-139210.html">Oracle [8]</a>.</p> -<p>Clean the ANT_HOME variable, delete the <i>build, bootstrap</i> and <i>dist</i> directory -and point JAVA_HOME to the JDK 1.2 home directory. Then do the <tt>build</tt>, set ANT_HOME -and run <tt>ant test</tt> (like above).</p> +<p>Clean the <code>ANT_HOME</code> variable, delete the <samp>build</samp>, <samp>bootstrap</samp> and <samp>dist</samp> +directories, and point <code>JAVA_HOME</code> to the JDK 5 home directory. Then create the patch with your commit, +checkout 1.9.x branch in Git, apply your patch and do the <code>build</code>, set <code>ANT_HOME</code> and +run <code>ant test</code> (like above).</p> <p>Our test should pass.</p> <h3>Checkstyle</h3> -<p>There are many things we have to ensure. Indentation with 4 spaces, blanks here and there, ... -(all described in the <a href="http://ant.apache.org/ant_task_guidelines.html">Ant Task Guidelines [6]</a> which -includes the <a href="http://www.oracle.com/technetwork/java/codeconvtoc-136057.html">Sun code style -[9]</a>). Because there are so many things we would be happy to have a tool for do the checks. -There is one: checkstyle. Checkstyle is available at <a href="http://checkstyle.sourceforge.net/"> -Sourceforge [10]</a> and Ant provides with the <tt>check.xml</tt> a buildfile which will do the job -for us.</p> - -<p>Download it and put the checkstyle-*-all.jar into your %USERPROFILE%\.ant\lib directory. -All jar's stored there are available to Ant so you haven't to add it to you %ANT_HOME%\lib -directory (this feature was added with Ant 1.6).</p> +<p>There are many things we have to ensure. Indentation with 4 spaces, blanks here and there, ... (all described in +the <a href="https://ant.apache.org/ant_task_guidelines.html">Ant Task Guidelines [6]</a> which includes +the <a href="https://www.oracle.com/technetwork/java/codeconvtoc-136057.html">Sun code style [9]</a>). Because there are +so many things we would be happy to have a tool for do the checks. There is one: checkstyle. Checkstyle is available +at <a href="http://checkstyle.sourceforge.net/"> Sourceforge [10]</a> and Ant provides with the <samp>check.xml</samp> a +buildfile which will do the job for us.</p> + +<p>Download it and put the <samp>checkstyle-*-all.jar</samp> into your <samp>%USERPROFILE%\.ant\lib</samp> directory. +All jar's stored there are available to Ant so you haven't to add it to you <samp>%ANT_HOME%\lib</samp> directory (this +feature is available <em>since Ant 1.6</em>).</p> <p>So we will run the tests with</p> -<pre class="output"> -ANTHOME> ant -f check.xml checkstyle htmlreport -</pre> -<p>I prefer the HTML report because there are lots of messages and we can navigate faster. -Open the ANTHOME/build/reports/checkstyle/html/index.html and navigate to the Find.java. Now we -see that there are some errors: missing whitespaces, unused imports, missing javadocs. So we have -to do that.</p> +<pre class="output">ANTREPO> ant -f check.xml checkstyle htmlreport</pre> +<p>I prefer the HTML report because there are lots of messages and we can navigate faster. Open +the <samp>ANTREPO/build/reports/checkstyle/html/index.html</samp> and navigate to the <samp>Find.java</samp>. Now we see +that there are some errors: missing whitespaces, unused imports, missing javadocs. So we have to do that.</p> -<p>Hint: start at the <b>buttom</b> of the file so the line numbers in the report will keep -up to date and you will find the next error place much more easier without redoing the checkstyle.</p> +<p>Hint: start at the <strong>bottom</strong> of the file so the line numbers in the report will keep up to date and you +will find the next error place much more easier without redoing the checkstyle.</p> -<p>After cleaning up the code according to the messages we delete the reports directory and -do a second checkstyle run. Now our task isn't listed. That's fine :-)</p> - -<!-- - Couldnt create the diff that way for myself, but that should be documented. - But on the other hand this tutorial should not be forgotten any longer so I - comment that out. JHM -<h3>Creating the diff</h3> -<p>Creating a diff for Ant is very easy: just start <tt>ant -f patch.xml</tt> and all is done -automatically. This step requires a cvs executable in your path and internet access (more precise: -cvs access). As a result we get a file <i> TODO </i>.</p> ---> +<p>After cleaning up the code according to the messages we delete the reports directory and do a second checkstyle +run. Now our task isn't listed. That's fine :-)</p> <h3>Publish the task</h3> -<p>Finally we publish that archive. As described in the <a href="http://ant.apache.org/ant_task_guidelines.html"> -Ant Task Guidelines [7]</a> we can post it on the developer mailinglist or we create a BugZilla -entry. For both we need some information:</p> +<p>Finally we publish that archive. As described in the <a href="https://ant.apache.org/ant_task_guidelines.html">Ant +Task Guidelines [7]</a> we can announce it on the developer mailing list, create a BugZilla entry and open a GitHub pull +request. For both we need some information:</p> <table> <tr> +<!-- this is an empty "table head" --> +</tr> +<tr> <th>subject</th> - <td><i>short description</i></td> + <td><em>short description</em></td> <td>Task for finding files in a path</td> </tr> <tr> <th>body</th> - <td><i>more details about the path</i></td> - <td>This new task looks inside a nested <code><path/></code> for occurrences of a file and stores - all locations as a property. See the included manual for details.</td> + <td><em>more details about the path</em></td> + <td>This new task looks inside a nested <code><path/></code> for occurrences of a file and stores all locations + as a property. See the included manual for details.</td> </tr> <tr> - <th>attachments</th> - <td><i>all files needed to apply the path</i></td> - <td>Archive containing a patch with the new and modified resources</td> + <th>pull request reference</th> + <td><em>GitHub pull request URL</em></td> + <td>https://github.com/apache/ant/pull/0</td> </tr> </table> -<p>Sending an email with these information is very easy and I think I haven't to show that. -The other way - BugZilla - is slightly more difficult. But it has the advantage that entries -will not be forgotten (once per week a report is generated). So I will show this way.</p> +<p>Sending an email with this information is very easy and I think I haven't to describe that. BugZilla is slightly +more difficult. But the advantage is that entries will not be forgotten (a report is generated once every weekend). So +I will describe the process.</p> -<p>You must have a BugZilla account for that. So open the <a href="http://issues.apache.org/bugzilla/"> -BugZilla Main Page [11]</a> and follow the link -<a href="http://issues.apache.org/bugzilla/createaccount.cgi">Open a new Bugzilla account [12]</a> -and the steps described there if you haven't one.</p> +<p>First, you must have a BugZilla account. So open the <a href="https://issues.apache.org/bugzilla/">BugZilla Main Page +[11]</a> and follow the link <a href="https://issues.apache.org/bugzilla/createaccount.cgi">Open a new Bugzilla account +[12]</a> and the steps described there if you haven't one.</p> <ol> -<li>From the BugZilla main page choose <a href="http://issues.apache.org/bugzilla/enter_bug.cgi">Enter - a new bug report [13]</a></li> -<li>Choose "Ant" as product </li> -<li>Version is the last "Alpha (nightly)" (at this time 1.7)</li> +<li>From the BugZilla main page choose <a href="https://issues.apache.org/bugzilla/enter_bug.cgi">Enter a new bug report + [13]</a></li> +<li>Choose "Ant" as product</li> +<li>Version is the last "Alpha (nightly)" (at this time 1.10)</li> <li>Component is "Core tasks"</li> <li>Platform and Severity are ok with "Other" and "Normal"</li> <li>Initial State is ok with "New"</li> <li>Same with the empty "Assigned to"</li> -<li>It is not required to add yourself as CC, because you are the reporter and therefore will be - informed on changes</li> -<li>URL: no url required</li> -<li>Summary: add the <i>subject</i> from the table</li> -<li>Description: add the <i>body</i> from the table</li> -<li>Then press "Commit"</li> -<li>After redirecting to the new created bug entry click "Create a New Attachment"</li> -<li>Enter the path to your local path file into "File" or choose it via the "File"'s - button.</li> -<li>Enter a short description into "Description", so that you could guess, what the - path file includes. Here we could add "Initial Patch".</li> -<li>The "Content Type" is "auto-detect". You could use the "patch" type, if you only - provide a single path file, but we want do upload more that one, included in our - patch.zip.</li> +<li>It is not required to add yourself as CC, because you are the reporter and therefore will be informed on + changes</li> +<li>URL: GitHub pull request URL</li> +<li>Summary: add the <var>subject</var> from the table</li> +<li>Description: add the <var>body</var> from the table</li> <li>Then press "Commit"</li> </ol> -Now the new task is uploaded into the bug database. + +<p>Now the new task is registered in the bug database.</p> <h2 id="resources">Resources</h2> <ol class="refs"> @@ -954,20 +856,15 @@ Now the new task is uploaded into the bug database. <li><a href="properties.html#built-in-props">properties.html#built-in-props</a></li> <li><a href="http://ant-contrib.sourceforge.net/">http://ant-contrib.sourceforge.net/</a></li> <li><a href="Tasks/java.html">Tasks/java.html</a></li> - <li><a href="http://ant.apache.org/ant_task_guidelines.html">http://ant.apache.org/ant_task_guidelines.html</a></li> - <li><a href="http://ant.apache.org/cvs.html">http://ant.apache.org/cvs.html</a></li> - <li><a href="http://www.oracle.com/technetwork/java/archive-139210.html">http://www.oracle.com/technetwork/java/archive-139210.html</a></li> - <li><a href="http://www.oracle.com/technetwork/java/codeconvtoc-136057.html">http://www.oracle.com/technetwork/java/codeconvtoc-136057.html</a></li> + <li><a href="https://ant.apache.org/ant_task_guidelines.html">https://ant.apache.org/ant_task_guidelines.html</a></li> + <li><a href="https://github.com/apache/ant">https://github.com/apache/ant</a></li> + <li><a href="https://www.oracle.com/technetwork/java/archive-139210.html">https://www.oracle.com/technetwork/java/archive-139210.html</a></li> + <li><a href="https://www.oracle.com/technetwork/java/codeconvtoc-136057.html">https://www.oracle.com/technetwork/java/codeconvtoc-136057.html</a></li> <li><a href="http://checkstyle.sourceforge.net/">http://checkstyle.sourceforge.net/</a></li> - <li><a href="http://issues.apache.org/bugzilla/">http://issues.apache.org/bugzilla/</a></li> - <li><a href="http://issues.apache.org/bugzilla/createaccount.cgi">http://issues.apache.org/bugzilla/createaccount.cgi</a></li> - <li><a href="http://issues.apache.org/bugzilla/enter_bug.cgi">http://issues.apache.org/bugzilla/enter_bug.cgi</a></li> + <li><a href="https://issues.apache.org/bugzilla/">https://issues.apache.org/bugzilla/</a></li> + <li><a href="https://issues.apache.org/bugzilla/createaccount.cgi">https://issues.apache.org/bugzilla/createaccount.cgi</a></li> + <li><a href="https://issues.apache.org/bugzilla/enter_bug.cgi">https://issues.apache.org/bugzilla/enter_bug.cgi</a></li> </ol> -<!-- - TODO: - - how to create a path (path.xml / command line) ---> - </body> </html> |