From b9421dc80af485591a9c50cc8921f912e0def11e Mon Sep 17 00:00:00 2001 From: Ashlee Young Date: Fri, 23 Oct 2015 10:05:40 -0700 Subject: Removing sources to replace with download links instead. Change-Id: Ie28789a725051aec0d1b04dd291b7690a7898668 Signed-off-by: Ashlee Young --- .../manual/tutorial-tasks-filesets-properties.html | 993 --------------------- 1 file changed, 993 deletions(-) delete mode 100644 framework/src/ant/apache-ant-1.9.6/manual/tutorial-tasks-filesets-properties.html (limited to 'framework/src/ant/apache-ant-1.9.6/manual/tutorial-tasks-filesets-properties.html') diff --git a/framework/src/ant/apache-ant-1.9.6/manual/tutorial-tasks-filesets-properties.html b/framework/src/ant/apache-ant-1.9.6/manual/tutorial-tasks-filesets-properties.html deleted file mode 100644 index 3a36e7ef..00000000 --- a/framework/src/ant/apache-ant-1.9.6/manual/tutorial-tasks-filesets-properties.html +++ /dev/null @@ -1,993 +0,0 @@ - - - - - Tutorial: Tasks using Properties, Filesets & Paths - - -

Tutorial: Tasks using Properties, Filesets & Paths

- -

After reading the tutorial about writing -tasks [1] 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.

- -

Content

-

- - -

The goal

-

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.

- - -

Build environment

-

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. :-)

-
-<?xml version="1.0" encoding="ISO-8859-1"?>
-<project name="FindTask" basedir="." default="test">
-    ...
-    <target name="use.init" description="Taskdef's the Find-Task" depends="jar">
-        <taskdef name="find" classname="Find" classpath="${ant.project.name}.jar"/>
-    </target>
-
-    <!-- the other use.* targets are deleted -->
-    ...
-</project>
-
- -

The buildfile is in the archive -tutorial-tasks-filesets-properties.zip [2] in /build.xml.01-propertyaccess -(future version saved as *.02..., final version as build.xml; same for sources).

- - -

Property access

-

Our first step is to set a property to a value and print the value of that property. -So our scenario would be -

-    <find property="test" value="test-value"/>
-    <find print="test"/>
-
-ok, can be rewritten with the core tasks -
-    <property name="test" value="test-value"/>
-    <echo message="${test}"/>
-
-but I have to start on known ground :-)

-

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: - -

-import org.apache.tools.ant.BuildException;
-
-public class Find extends Task {
-
-    private String property;
-    private String value;
-    private String print;
-
-    public void setProperty(String property) {
-        this.property = property;
-    }
-
-    // setter for value and print
-
-    public void execute() {
-        if (print != null) {
-            String propValue = getProject().getProperty(print);
-            log(propValue);
-        } else {
-            if (property == null) throw new BuildException("property not set");
-            if (value    == null) throw new BuildException("value not set");
-            getProject().setNewProperty(property, value);
-        }
-    }
-}
-
- -As said in the other tutorial, the property access is done via Project instance. -We get this instance via the public getProject() method which we inherit from -Task (more precise from ProjectComponent). Reading a property is done via -getProperty(propertyname) (very simple, isn't it?). This property returns -the value as String or null if not set.
-Setting a property is ... not really difficult, but there is more than one setter. You can -use the setProperty() method which will do the job like expected. But there is -a golden rule in Ant: properties are immutable. And this method sets the property -to the specified value - whether it has a value before that or not. So we use another -way. setNewProperty() sets the property only if there is no property with that -name. Otherwise a message is logged.

- -

(by the way: a short word to ants "namespaces" (don't -be confused with xml namespaces: -an <antcall> 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.)

- -

There are some other setter, too (but I haven't used them, so I can't say something -to them, sorry :-)

- -

After putting our two line example from above into a target names use.simple -we can call that from our testcase: - -

-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");
-    }
-
-    @Test
-    public void testSimple() {
-        buildRule.executeTarget("useSimgle");
-        Assert.assertEquals("test-value", buildRule.getLog());
-    }
-}
-
- -and all works fine.

- - - -

Using filesets

-

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 -

-    <find file="ant.jar" location="location.ant-jar">
-        <fileset dir="${ant.home}" includes="**/*.jar"/>
-    </find>
-
-

- -

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: -

-public class Find extends Task {
-
-    private String file;
-    private String location;
-    private Vector filesets = new Vector();
-
-    public void setFile(String file) {
-        this.file = file;
-    }
-
-    public void setLocation(String location) {
-        this.location = location;
-    }
-
-    public void addFileset(FileSet fileset) {
-        filesets.add(fileset);
-    }
-
-    public void execute() {
-    }
-}
-
-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).

- -

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?

-Maybe you find some more testcases. But this is enough for now.
-For each of these points we create a testXX method.

- -
-public class FindTest {
-
-    @Rule
-    public final BuildFileRule buildRule = new BuildFileRule();
-
-    ... // constructor, setUp as above
-
-    @Test
-    public void testMissingFile() {
-        Find find = new Find();
-        try {
-            find.execute();
-            fail("No 'no-file'-exception thrown.");
-        } catch (Exception e) {
-            // exception expected
-            String expected = "file not set";
-            assertEquals("Wrong exception message.", expected, e.getMessage());
-        }
-    }
-
-    @Test
-    public void testMissingLocation() {
-        Find find = new Find();
-        find.setFile("ant.jar");
-        try {
-            find.execute();
-            fail("No 'no-location'-exception thrown.");
-        } catch (Exception e) {
-            ... // similar to testMissingFile()
-        }
-    }
-
-    @Test
-    public void testMissingFileset() {
-        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
-    public void testFileNotPresent() {
-        buildRule.executeTarget("testFileNotPresent");
-        String result = buildRule.getProject().getProperty("location.ant-jar");
-        assertNull("Property set to wrong value.", result);
-    }
-
-    @Test
-    public void testFilePresent() {
-        buildRule.executeTarget("testFilePresent");
-        String result = buildRule.getProject().getProperty("location.ant-jar");
-        assertNotNull("Property not set.", result);
-        assertTrue("Wrong file found.", result.endsWith("ant.jar"));
-    }
-}
-
- -

If we run this test class all test cases (except testFileNotPresent) fail. Now we -can implement our task, so that these test cases will pass.

- -
-    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");
-    }
-
-    public void execute() {
-        validate();                                                             // 1
-        String foundLocation = null;
-        for(Iterator itFSets = filesets.iterator(); itFSets.hasNext(); ) {      // 2
-            FileSet fs = (FileSet)itFSets.next();
-            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)) {
-                    File base  = ds.getBasedir();                               // 5
-                    File found = new File(base, includedFiles[i]);
-                    foundLocation = found.getAbsolutePath();
-                }
-            }
-        }
-        if (foundLocation!=null)                                                // 6
-            getProject().setNewProperty(location, foundLocation);
-    }
-
- -

On //1 we check the prerequisites for our task. Doing that in a validate-method -is a common way, because we separate the prerequisites from the real work. On //2 we iterate -over all nested filesets. If we don't want to handle multiple filesets, the addFileset() -method has to reject the further calls. We can get the result of a fileset via its DirectoryScanner -like done in //3. After that we create a platform independent String representation of -the file path (//4, can be done in other ways of course). We have to do the replace(), -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 //5, 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 (//6).

- -

Ok, much more easier in this simple case would be to add the file as additional -include element to all filesets. But I wanted to show how to handle complex situations -without being complex :-)

- -

The test case uses the ant property ant.home as reference. This property is set by the -Launcher class which starts ant. We can use that property in our buildfiles as a -build-in property [3]. But if we create a new ant -environment we have to set that value for our own. And we use the <junit> task in fork-mode. -Therefore we have do modify our buildfile: -

-    <target name="junit" description="Runs the unit tests" depends="jar">
-        <delete dir="${junit.out.dir.xml}"/>
-        <mkdir  dir="${junit.out.dir.xml}"/>
-        <junit printsummary="yes" haltonfailure="no">
-            <classpath refid="classpath.test"/>
-            <sysproperty key="ant.home" value="${ant.home}"/>
-            <formatter type="xml"/>
-            <batchtest fork="yes" todir="${junit.out.dir.xml}">
-                <fileset dir="${src.dir}" includes="**/*Test.java"/>
-            </batchtest>
-        </junit>
-    </target>
-
- - -

Using nested paths

-

A task providing support for filesets is a very comfortable one. But there is another -possibility of bundling files: the <path>. 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 -<filelist> instead? <path>s combines these datatypes in that way that a path contains -other paths, filesets, dirsets and filelists. This is why -Ant-Contribs [4] <foreach> task is modified to support paths instead of filesets. So we want that, -too.

- -

Changing from fileset to path support is very easy:

-
-Change java code from:
-    private Vector filesets = new Vector();
-    public void addFileset(FileSet fileset) {
-        filesets.add(fileset);
-    }
-to:
-    private Vector paths = new Vector();                      *1
-    public void addPath(Path path) {                          *2
-        paths.add(path);
-    }
-and build file from:
-    <find file="ant.jar" location="location.ant-jar">
-        <fileset dir="${ant.home}" includes="**/*.jar"/>
-    </find>
-to:
-    <find file="ant.jar" location="location.ant-jar">
-        <path>                                                *3
-            <fileset dir="${ant.home}" includes="**/*.jar"/>
-        </path>
-    </find>
-
-

On *1 we rename only the vector. It�s just for better reading the source. On *2 -we have to provide the right method: an addName(Type t). Therefore replace the -fileset with path here. Finally we have to modify our buildfile on *3 because our task -doesn�t support nested filesets any longer. So we wrap the fileset inside a path.

- -

And now we modify the testcase. Oh, not very much to do :-) Renaming the testMissingFileset() -(not really a must-be but better it�s named like the think it does) and update the -expected-String in that method (now a path not set message is expected). The more complex -test cases base on the buildscript. So the targets testFileNotPresent and testFilePresent have to be -modified in the manner described above.

- -

The test are finished. Now we have to adapt the task implementation. The easiest modification is -in the validate() method where we change le last line to if (paths.size()<1) throw new -BuildException("path not set");. In the execute() 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:

- -
-    public void execute() {
-        validate();
-        String foundLocation = null;
-        for(Iterator itPaths = paths.iterator(); itPaths.hasNext(); ) {
-            Path path = (Path)itPaths.next();                                // 1
-            String[] includedFiles = path.list();                            // 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)) {
-                    foundLocation = includedFiles[i];                        // 3
-                }
-            }
-        }
-        if (foundLocation!=null)
-            getProject().setNewProperty(location, foundLocation);
-    }
-
- -

Of course we have to do the typecase to Path on //1. On //2 and //3 -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).

- - - -

Returning a list

-

So far so good. But could a file be on more than one place in the path? - Of course.
-And would it be good to get all of them? - It depends on ...

- -

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 <foreach>. All list -elements are concatenated and separated with a customizable separator (default ',').

- -

So we do the following:

- -
-    <find ... delimiter=""/> ... </find>
-
- -

If the delimiter is set we will return all found files as list with that delimiter.

- -

Therefore we have to

- -

So we add as testcase:

-
-in the buildfile:
-    <target name="test.init">
-        <mkdir dir="test1/dir11/dir111"/>                             *1
-        <mkdir dir="test1/dir11/dir112"/>
-        ...
-        <touch file="test1/dir11/dir111/test"/>
-        <touch file="test1/dir11/dir111/not"/>
-        ...
-        <touch file="test1/dir13/dir131/not2"/>
-        <touch file="test1/dir13/dir132/test"/>
-        <touch file="test1/dir13/dir132/not"/>
-        <touch file="test1/dir13/dir132/not2"/>
-        <mkdir dir="test2"/>
-        <copy todir="test2">                                          *2
-            <fileset dir="test1"/>
-        </copy>
-    </target>
-
-    <target name="testMultipleFiles" depends="use.init,test.init">    *3
-        <find file="test" location="location.test" delimiter=";">
-            <path>
-                <fileset dir="test1"/>
-                <fileset dir="test2"/>
-            </path>
-        </find>
-        <delete>                                                      *4
-            <fileset dir="test1"/>
-            <fileset dir="test2"/>
-        </delete>
-    </target>
-
-in the test class:
-    public void testMultipleFiles() {
-        executeTarget("testMultipleFiles");
-        String result = getProject().getProperty("location.test");
-        assertNotNull("Property not set.", result);
-        assertTrue("Only one file found.", result.indexOf(";") > -1);
-    }
-
- -

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 *1 and *2. And of course we clean up that on *4. The creation -can be done inside our test target or in a separate one, which will be better -for reuse later (*3). - -

The task implementation is modified as followed:

- -
-    private Vector foundFiles = new Vector();
-    ...
-    private String delimiter = null;
-    ...
-    public void setDelimiter(String delim) {
-        delimiter = delim;
-    }
-    ...
-    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('\\','/');
-                filename = filename.substring(filename.lastIndexOf("/")+1);
-                if (file.equals(filename) && !foundFiles.contains(includedFiles[i])) {   // 1
-                    foundFiles.add(includedFiles[i]);
-                }
-            }
-        }
-
-        // create the return value (list/single)
-        String rv = null;
-        if (foundFiles.size() > 0) {                                        // 2
-            if (delimiter==null) {
-                // only the first
-                rv = (String)foundFiles.elementAt(0);
-            } else {
-                // create list
-                StringBuffer list = new StringBuffer();
-                for(Iterator it=foundFiles.iterator(); it.hasNext(); ) {    // 3
-                    list.append(it.next());
-                    if (it.hasNext()) list.append(delimiter);               // 4
-                }
-                rv = list.toString();
-            }
-        }
-
-        // create the property
-        if (rv!=null)
-            getProject().setNewProperty(location, rv);
-    }
-
- -

The algorithm does: finding all files, creating the return value depending on the users -wish, returning the value as property. On //1 we eliminates the duplicates. //2 -ensures that we create the return value only if we have found one file. On //3 we -iterate over all found files and //4 ensures that the last entry has no trailing -delimiter.

- -

Ok, first searching for all files and then returning only the first one ... You can -tune the performance of your own :-)

- - -

Documentation

-

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.

- -

If you have a look at the manual page of the Java task [5] - you will see that it:

-As a template we have: - -
-<html>
-
-<head>
-<meta http-equiv="Content-Language" content="en-us">
-<title>Taskname Task</title>
-</head>
-
-<body>
-
-<h2><a name="taskname">Taskname</a></h2>
-<h3>Description</h3>
-<p> Describe the task.</p>
-
-<h3>Parameters</h3>
-<table border="1" cellpadding="2" cellspacing="0">
-  <tr>
-    <td valign="top"><b>Attribute</b></td>
-    <td valign="top"><b>Description</b></td>
-    <td align="center" valign="top"><b>Required</b></td>
-  </tr>
-
-  do this html row for each attribute (including inherited attributes)
-  <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>
-  </tr>
-
-</table>
-
-<h3>Parameters specified as nested elements</h3>
-
-Describe each nested element (including inherited)
-<h4>your nested element</h4>
-<p>description</p>
-<p><em>since Ant 1.6</em>.</p>
-
-<h3>Examples</h3>
-<pre>
-    A code sample; don't forget to escape the < of the tags with &lt;
-</pre>
-What should that example do?
-
-</body>
-</html>
-
- -

Here is an example documentation page for our task:

-
-<html>
-
-<head>
-<meta http-equiv="Content-Language" content="en-us">
-<title>Find Task</title>
-</head>
-
-<body>
-
-<h2><a name="find">Find</a></h2>
-<h3>Description</h3>
-<p>Searchs 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 border="1" cellpadding="2" cellspacing="0">
-  <tr>
-    <td valign="top"><b>Attribute</b></td>
-    <td valign="top"><b>Description</b></td>
-    <td align="center" valign="top"><b>Required</b></td>
-  </tr>
-  <tr>
-    <td valign="top">file</td>
-    <td valign="top">The name of the file to search.</td>
-    <td align="center" valign="top">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>
-  </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>
-  </tr>
-</table>
-
-<h3>Parameters specified as nested elements</h3>
-
-<h4>path</h4>
-<p>The path where to search the file.</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).
-
-<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).
-
-</body>
-</html>
-
- - -

Contribute the new task

-If we decide to contribute our task, we should do some things: -The Ant Task Guidelines [6] support additional -information on that.

- -

Now we will check the "Checklist before submitting a new task" described in that guideline. -

- - -

Package / Directories

-

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: org.apache.tools.ant.taskdefs. Implementations are in the -directory src/main, tests in src/testcases and buildfiles for -tests in src/etc/testcases.

- -

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 Access the Source Tree (AnonCVS) -[7] (password is anoncvs):

-cvs -d :pserver:anoncvs@cvs.apache.org:/home/cvspublic login                 //1
-cvs -d :pserver:anoncvs@cvs.apache.org:/home/cvspublic checkout ant          //2
-
-If you have a local copy of Ants sources just do an update -
-cvs -d :pserver:anoncvs@cvs.apache.org:/home/cvspublic login
-cd ant                                                                       //3
-cvs -d :pserver:anoncvs@cvs.apache.org:/home/cvspublic update                //4
-

- -

We use the -d flag on //1 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 //2 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 //3 and do the update -on //4.

- -

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): -

-ANTHOME> build                                                    // 1
-ANTHOME> set ANT_HOME=%CD%\dist                                   // 2
-ANTHOME> ant test -Dtest.haltonfailure=false                      // 3
-
- -First we have to build our Ant distribution (//1). On //2 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 //3 we let Ant do all the tests (which enforced a compile -of all tests) without stopping on first failure.

- -

Next we apply our work onto Ants sources. Because we haven't modified any, this is -a relative simple step. (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 :-). - -

- -Now our modifications are done and we will retest it: -
-ANTHOME> build
-ANTHOME> ant run-single-test                                      // 1
-             -Dtestcase=org.apache.tools.ant.taskdefs.FindTest    // 2
-             -Dtest.haltonfailure=false
-
-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 (//1 + 2).

- -

And ... oh, all tests fail: Ant could not find the task or a class this task relies upon.

- -

Ok: in the earlier steps we told Ant to use the Find class for the <find> task (remember the -<taskdef> 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 find=org.apache.tools.ant.taskdefs.Find as the last core -task (just before the # optional tasks line). Now a second try: -

-ANTHOME> build                                                    // 1
-ANTHOME> ant run-single-test
-             -Dtestcase=org.apache.tools.ant.taskdefs.FindTest
-             -Dtest.haltonfailure=false
-
-We have to rebuild (//1) 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. -
-ANTHOME> ant test -Dtest.haltonfailure=false
-
-Because there are a lot of tests this step requires a little bit of time. So use the run-single-test -during development and do the test only at the end (maybe sometimes during development too). -We use the -Dtest.haltonfailure=false here because there could be other tests fail and we have -to look into them.

- -

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).

- - - -

Apache license statement

-

Simply copy the license text from one the other source from the Ant source tree.

- - -

Test on JDK 1.2

-

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 Oracle [8].

- -

Clean the ANT_HOME variable, delete the build, bootstrap and dist directory -and point JAVA_HOME to the JDK 1.2 home directory. Then do the build, set ANT_HOME -and run ant test (like above).

- -

Our test should pass.

- - - -

Checkstyle

-

There are many things we have to ensure. Indentation with 4 spaces, blanks here and there, ... -(all described in the Ant Task Guidelines [6] which -includes the Sun code style -[9]). 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 -Sourceforge [10] and Ant provides with the check.xml a buildfile which will do the job -for us.

- -

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).

- -

So we will run the tests with -

-ANTHOME> ant -f check.xml checkstyle htmlreport
-
-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.

- -

Hint: start at the buttom 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.

- -

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 :-)

- - - - - - -

Publish the task

-

Finally we publish that archive. As described in the -Ant Task Guidelines [7] we can post it on the developer mailinglist or we create a BugZilla -entry. For both we need some information:

- - - - - - - - - - - - - - - - - -
subjectshort descriptionTask for finding files in a path
bodymore details about the pathThis new task looks inside a nested <path/> for occurrences of a file and stores - all locations as a property. See the included manual for details.
attachmentsall files needed to apply the pathArchive containing a patch with the new and modified resources
- -

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.

- -

You must have a BugZilla account for that. So open the -BugZilla Main Page [11] and follow the link -Open a new Bugzilla account [12] -and the steps described there if you haven't one.

- -
    -
  1. From the BugZilla main page choose Enter - a new bug report [13]
  2. -
  3. Choose "Ant" as product
  4. -
  5. Version is the last "Alpha (nightly)" (at this time 1.7)
  6. -
  7. Component is "Core tasks"
  8. -
  9. Platform and Severity are ok with "Other" and "Normal"
  10. -
  11. Initial State is ok with "New"
  12. -
  13. Same with the empty "Assigned to"
  14. -
  15. It is not required to add yourself as CC, because you are the reporter and therefore will be - informed on changes
  16. -
  17. URL: no url required
  18. -
  19. Summary: add the subject from the table
  20. -
  21. Description: add the body from the table
  22. -
  23. Then press "Commit"
  24. -
  25. After redirecting to the new created bug entry click "Create a New Attachment"
  26. -
  27. Enter the path to your local path file into "File" or choose it via the "File"'s - button.
  28. -
  29. Enter a short description into "Description", so that you could guess, what the - path file includes. Here we could add "Initial Patch".
  30. -
  31. 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.
  32. -
  33. Then press "Commit"
  34. -
-Now the new task is uploaded into the bug database. - - -

Resources

-  [1] tutorial-writing-tasks.html
-  [2] tutorial-tasks-filesets-properties.zip
-  [3] properties.html#built-in-props
-  [4] http://ant-contrib.sourceforge.net/
-  [5] Tasks/java.html
-  [6] http://ant.apache.org/ant_task_guidelines.html
-  [7] http://ant.apache.org/cvs.html
-  [8] http://www.oracle.com/technetwork/java/archive-139210.html
-  [9] http://www.oracle.com/technetwork/java/codeconvtoc-136057.html
-  [10] http://checkstyle.sourceforge.net/
-  [11] http://issues.apache.org/bugzilla/
-  [12] http://issues.apache.org/bugzilla/createaccount.cgi
-  [13] http://issues.apache.org/bugzilla/enter_bug.cgi
- - - - - - - - - - -- cgit 1.2.3-korg