============================ Project Automation Using Ant ============================ :Author: Nick Efford :Contact: N.D.Efford@leeds.ac.uk :Status: Final :Revised: 2017-09-13 The objectives of this worksheet are for you to learn the main features of the Ant_ build tool, for you to gain experience of running Ant from the command line and for you to see how Ant is used within Intellij IDEA. You may find it useful to consult the `Ant manual`_ as you carry out the tasks below. .. _Ant: http://ant.apache.org/ .. _Ant manual: http://ant.apache.org/manual/ Getting Started =============== #. Create a directory in your filestore for this worksheet, then download Zip archive :download:`Ant.zip` into that directory. #. Unpack the Zip archive - e.g., using the ``unzip`` command in a terminal window. This will give you a directory tree like the following .. code-block:: none build.xml lib/ hamcrest-core-1.3.jar junit-4.12.jar scripts/ alarmclock.bat alarmclock.sh clock.bat clock.sh src/ comp2931/ time/ AlarmClock.java Clock.java Time.java TimeTest.java Spend a couple of minutes examining these files. Ant Concepts ============ The file :file:`build.xml` is an **Ant buildfile**. Open it in an ordinary text editor such as Atom or gedit. You should see this: .. literalinclude:: build.xml :language: xml :linenos: * Everything is defined inside a ``project`` element, which has attributes to specify the project name and the base directory from which all paths to files and directories are computed. * Inside the ``project`` element are four **property settings** (lines 4-7). Rather like variables in a program, these provide a single point of definition for frequently-used values, making it easier to change those values in future. In this case, the buildfile defines properties specifying the three existing directories plus one that doesn't yet exist. The latter is where the ``.class`` files produced by the compiler will be stored. * After the properties is a **path definition** (lines 9-13). This defines the project's classpath - i.e., the path that will be used to find classes when invoking the Java compiler or JVM. * After the path definition are three **targets**, with names ``init``, ``compile`` and ``clean``. Targets are sets of tasks to be peformed by Ant. You specify one or more targets to be executed when you run Ant. The ``compile`` target contains the ``javac`` task, which runs the Java compiler on the code in the directory subtree specified by property ``src.dir``. Notice that ``compile`` depends on ``init``. This means that ``init`` will run if necessary before ``compile`` runs. In this case, ``init`` simply runs the ``mkdir`` task to create the subdirectory for compiled code. Basic Usage =========== #. In a terminal window, cd to the directory containing the buildfile and enter the command ``ant -h``. This will show you the various options that can be specified when running Ant. #. Enter ``ant -p``. This provides 'project help' by listing the targets defined in the buildfile. #. Run the ``compile`` target by entering ``ant compile``. Ant will report on the tasks it is executing. (You can suppress this using the ``-q`` option.) Notice that ``init`` runs first. Use ``ls`` to list directory contents. Notice that a ``bin`` directory now exists. Look into the subdirectories of ``bin`` and you will find the ``.class`` files generated by the compiler. #. Enter ``ant compile`` a second time. Ant will do nothing because the ``bin`` directory already exists and the bytecode it contains is up-to-date. #. Edit one of the ``.java`` files under ``src`` and make a trivial change to one of the files (such as altering one of the comments). Save your change, then go back to the command prompt and enter ``ant compile`` again. Notice that only the changed file is recompiled. #. Enter ``ant clean`` to remove the ``bin`` directory. #. Try entering ``ant`` with no arguments. Ant will run and report 'BUILD SUCCESSFUL', but it won't actually do anything because we haven't specified a default target. Specify one now by going to your text editor and adding ``default="compile"`` to the ``project`` tag at the start of the buildfile. Enter ``ant`` again with no arguments. The ``init`` and ``compile`` tasks will be executed. Running Applications ==================== We have two Java applications: ``Clock`` and ``AlarmClock``. The former simulates a clock by printing the current time once every second. The latter also displays the time but uses a Swing-based graphical user interface and adds the ability to set an alarm to a time specified via a command line argument. Let's add targets to run these applications. #. Edit ``build.xml`` and, beneath the ``compile`` target, add the following chunk of XML: .. code-block:: xml Notice the dependency on ``compile`` and the way in which the classpath is specified for the ``java`` task. Try running the ``Clock`` application by entering ``ant clock``. The application will run for 10 seconds and then stop. You can terminate it prematurely by pressing :kbd:`Ctrl+C`. #. Now add the following target to ``build.xml``: .. code-block:: xml Notice the use of ``fork="true"`` in the ``java`` task. This means that the application will run in a separate JVM rather than in the JVM that is running Ant. This ensures correct behaviour for Swing-based applications. The ``AlarmClock`` application requires a command line argument to specify alarm time, which we supply by nesting an ``arg`` element inside the ``java`` element. The value of ``+10`` means an offset of 10 seconds in the future. Try running ``AlarmClock`` by entering ``ant alarmclock``. After 10 seconds, the window should flash with a yellow background. You can disable the alarm by clicking on the background. The application can be shut down in the usual way. Running Tests ============= Ant provides the ``junit`` task, which can run unit tests using JUnit and collect the results. #. Add the following new target to ``build.xml``, beneath the ``alarmclock`` target: .. code-block:: xml The ``formatter`` element inside the task configures how test output will be collected. In this case, it will be displayed as plain text on screen rather than being directed to a file. The ``test`` element is used to specify the test classes you wish to run [#]_. #. Run the target with ``ant test``. Ant should run the ``junit`` target and report that 11 tests have passed, as well as listing the individual test cases and how long it took to execute them. (The latter can be avoided by specifying a formatter type of ``brief`` rather than ``plain``.) Generating Documentation ======================== Ant can run the Javadoc tool, which extracts information from comments in Java source code and generates HTML documentation for that code. #. Add the following to ``build.xml``, beneath the existing property definitions: .. code-block:: xml #. Now add a new target called ``docs`` that executes the ``javadoc`` task: .. code-block:: xml This target creates a new directory if necessary and then runs Javadoc, putting the generated HTML files in that directory. The ``fileset`` element specifies the files to be processed as everything under the ``src`` directory with a name that does not end in ``Test.java``. This ensures that documentation isn't generated for any unit testing classes. #. Run the new target by entering ``ant docs``. This should create a new directory called ``doc`` and then populate that directory with HTML pages generated for the ``Time``, ``Clock`` and ``AlarmClock`` classes. View this documentation by loading ``doc/index.html`` into a web browser. Adding Targets For Packaging ============================ It is often convenient to bundle the ``.class`` files for an application into a **JAR file** (Java Archive file). This makes distributing applications in executable form easier. We might also want to distribute code with accompanying documentation, bundling both together in a Zip archive. Ant supports both of these tasks. #. Add the following to ``build.xml``, beneath the existing property definitions: .. code-block:: xml These define the names and locations of the JAR file that will hold the compiled applications and a Zip archive that could be used to ship this JAR file plus other associated files (shell scripts and documentation) to users. #. Add the following target to support JAR file creation: .. code-block:: xml The ``jar`` target has successful compilation as a prerequisite. It packages the ``.class`` files under ``bin``, excluding ``TimeTest.class``, as a single JAR file called ``clocks.jar`` and puts this in the ``dist`` directory. This directory will be created if it doesn't already exist. Try this out now. Run the target with ``ant jar``, then move into the ``dist`` directory and try running the ``AlarmClock`` application like so: .. code-block:: none java -jar clocks.jar +10 #. Add the following target to support Zip archive creation: .. code-block:: xml The ``zip`` target expects a JAR file and Javadoc-generated documentation to be present and will execute the relevant targets if not. It packages these elements along with the scripts in the ``scripts`` directory as a single Zip archive. Try running the target now with ``ant zip``. You should see a ``.zip`` file created in the ``dist`` directory. Copy this file somewhere else, unzip it and try running the applications via the scripts. #. Finally, alter the existing clean-up target and add another one, so that you end up with the following code: .. code-block:: xml You now have two ways of cleaning up the project: ``ant clean`` will remove compiled code and documentation, leaving files for distribution untouched, whereas ``ant veryclean`` will remove all files generated by the other targets. Try the latter now. Try running ``ant zip`` again to see how the distributable Zip archive can be built from scratch with a single command. Using Ant With IntelliJ ======================= #. IntelliJ provides some rudimentary support for Ant buildfiles. To try this out, open an existing Java project - e.g. the ``JUnit`` project created for :doc:`/junit/main`. Once the project is open, choose :menuselection:`&Build --> &Generate Ant Build...`. On the resulting dialog, select the option to 'Generate single-file ant build' and specify ``build`` as the output file name. Then untick the checkbox for 'Enable UI forms compilation' and click :guilabel:`OK`. Two new files should be created in the project: :file:`build.xml` and :file:`build.properties`. #. Open :file:`build.xml` in the code editor. You will see that it is fairly complex. Fortunately, IntelliJ provides an easier way to interact with it. Click on the :guilabel:`Ant Build` tab, normally located on the right edge of the UI. The Ant Build tool window will slide out. Click on the green 'plus' button at the top of the tool window, select :file:`build.xml` on the resulting dialog and click :guilabel:`OK`. The targets from the buildfile should now appear in the Ant Build window. .. figure:: antbuild.png :align: center #. Right-click on the 'clean' target in the Ant Build window and choose :menuselection:`Run Target`. Activate the Messages tool window by clicking the :guilabel:`0: Messages` tab or by pressing :kbd:`Alt+0`. You should see a series of messages on the progress of the build displayed. These are organised hierarchically; you can double-click on entries to go deeper and get more detail. Now turn your attention to the Project tool window. If you expand the :file:`out` directory, you should see that its sudirectories are now empty. #. Right-click on the 'compile.module.testing' target in the Ant Build window and choose :menuselection:`Run Target`. This compiles both the ``Time`` class and the ``TimeTest`` class. If you check the :file:`out` folder again, you should see that the corresponding ``.class`` files have now been added. .. note:: Support for Ant in IntelliJ is limited. Automatically generated buildfiles contain targets to compile and clean a project, but if you want anything else (e.g., a target to run unit tests) you will need to add it yourself. Other build tools such as Gradle_ are better supported by IntelliJ. .. _Gradle: https://gradle.org ---- .. [#] If there are multiple test classes, you either use multiple ``test`` elements or use a ``batchtest`` element to tell Ant it should run all the test classes that match a particular pattern.)