Author: jdcasey
Date: Tue Jan 10 20:58:12 2006
New Revision: 367925
URL: http://svn.apache.org/viewcvs?rev=367925&view=rev
Log:
Corrected java plugin dev guide for updates to the plugin version manager, and
added an ant plugin dev guide. Will link in the Ant dev guide next.
Added:
maven/site/trunk/src/site/apt/guides/plugin/guide-ant-plugin-development.apt
(with props)
Modified:
maven/site/trunk/src/site/apt/guides/plugin/guide-java-plugin-development.apt
Added:
maven/site/trunk/src/site/apt/guides/plugin/guide-ant-plugin-development.apt
URL:
http://svn.apache.org/viewcvs/maven/site/trunk/src/site/apt/guides/plugin/guide-ant-plugin-development.apt?rev=367925&view=auto
==============================================================================
---
maven/site/trunk/src/site/apt/guides/plugin/guide-ant-plugin-development.apt
(added)
+++
maven/site/trunk/src/site/apt/guides/plugin/guide-ant-plugin-development.apt
Tue Jan 10 20:58:12 2006
@@ -0,0 +1,675 @@
+ ---
+ Guide to Developing Ant Plugins
+ ---
+ John Casey
+ ---
+ 09 January 2006
+ ---
+
+~~ Copyright 2001-2005 The Apache Software Foundation.
+~~
+~~ Licensed under the Apache License, Version 2.0 (the "License");
+~~ you may not use this file except in compliance with the License.
+~~ You may obtain a copy of the License at
+~~
+~~ http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~ Unless required by applicable law or agreed to in writing, software
+~~ distributed under the License is distributed on an "AS IS" BASIS,
+~~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+~~ See the License for the specific language governing permissions and
+~~ limitations under the License.
+
+~~ NOTE: This guide has been adapted from "Guide to Developing Java Plugins"
+~~ by Bob Allison.
+
+Introduction
+
+ The intent of this document is to help users learn to develop Maven plugins
+ using Ant.
+
+ As of the 2.0.1 release, Maven supports Ant-driven plugins. These plugins
+ allow the invocation of Ant targets (specified in scripts embedded in the
+ plugin jar) at specific points in the build lifecycle. They can also inject
+ parameter values into the Ant project instances when a target is called.
+
+*Conventions
+
+ In this guide, we'll use the standard Maven directory structure for projects,
+ to keep our POMs as simple as possible. It's important to note that this is
+ only a standard layout, not a requirement. The important locations for our
+ discussion are the following:
+
++---+
+ /<project-root>
+ |
+ +- pom.xml
+ |
+ +- /src
+ | |
+ | +- /main
+ | | |
+ | | +- /scripts (source location for script-driven plugins)
+ | | | |
+ ...
++---+
+
+*Getting Started
+
+ We'll start with the simplest of all possible plugins. This plugin takes no
+ parameters, and will simply print a message out to the screen when invoked.
+ This should familiarize the reader with the basics of mapping Ant build
scripts
+ to the Maven plugin framework. From there, we will gradually increase the
+ complexity of our plugin, adding parameters, interacting with standard
project
+ locations, and binding to lifecycle phases. Finally, we'll see how a single
Ant
+ build script can be mapped to multiple Maven mojos within the same plugin.
+
+**Hello, World
+
+ Our first plugin will simply print "Hello, World" to the console.
+
+***The Build Script
+
+ The elemental Ant-driven mojo consists of a simple Ant build script, a
mapping
+ metadata file, and of course the plugin's POM. If our goal is to print
"Hello, World",
+ we might use an Ant build script that looks something like this:
+
++---+
+hello.build.xml:
+--------------------------------
+
+ <!-- The specification of the "hello" default target here allows us to
+ simplify the mapping document for a single mojo, as below.
+ -->
+ <project default="hello">
+ <target name="hello">
+ <echo>Hello, World</echo>
+ </target>
+ </project>
++---+
+
+***The Mapping Document
+
+ Once we've created this build script, we need to tell Maven how to use it as
a
+ plugin. This involves creating a mapping document. Note that where the build
+ script was named <<hello.build.xml>>, the mapping document is named
+ <<hello.mojos.xml>>. The naming of these files is very important, as this is
how
+ the plugin parser matches mapping documents to build scripts. It has the
general
+ form:
+
+ * <basename><<.build.xml>> - The Ant build script.
+
+ * <basename><<.mojos.xml>> - The corresponding mapping document.
+
+ []
+
+ A simple mapping document used to wire the above build script into Maven's
+ plugin framework might look as follows:
+
++---+
+hello.mojos.xml:
+------------------------------
+
+ <pluginMetadata>
+ <mojos>
+ <mojo>
+ <goal>hello</goal>
+ <description>
+ Say Hello, World.
+ </description>
+ </mojo>
+ </mojos>
+ </pluginMetadata>
++---+
+
+***The POM
+
+ Now that we have the build script and mapping document, we're ready to build
+ this plugin. However, in order to build, we need to provide a POM for our new
+ plugin. As it turns out, the POM required for an Ant-driven plugin is fairly
+ complex. This is because we have to configure the maven-plugin-plugin to use
+ the Ant plugin parsing tools in addition to the defaults (such as the Java
+ parsing tools). Our POM might look something like this:
+
++---+
+pom.xml:
+------------------------------
+
+ <project>
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.myproject.plugins</groupId>
+ <artifactId>hello-plugin</artifactId>
+ <version>1.0-SNAPSHOT</version>
+
+ <packaging>maven-plugin</packaging>
+
+ <name>Hello Plugin</name>
+
+ <build>
+ <plugins>
+ <plugin>
+ <!-- NOTE: We don't need groupId if the plugin's groupId is
+ org.apache.maven.plugins OR org.codehaus.mojo.
+ We also don't have to specify a version, since Maven can
+ automatically resolve the newest one.
+ -->
+ <artifactId>maven-plugin-plugin</artifactId>
+
+ <!-- Add the Ant plugin tools -->
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-plugin-tools-ant</artifactId>
+ <version>2.0.1</version>
+ </dependency>
+ </dependencies>
+
+ <!-- Tell the plugin-plugin which prefix we will use.
+ Later, we'll configure Maven to allow us to invoke this
+ plugin using the "prefix:mojo" shorthand.
+ -->
+ <configuration>
+ <prefix>hello</prefix>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </project>
++---+
+
+***Build It and Run It
+
+ Once we have a POM for our new plugin, we can install it into the local
+ repository just as we would any other Maven project:
+
++---+
+mvn install
++---+
+
+ and invoke it like this:
+
++---+
+mvn org.myproject.plugins:hello-plugin:hello
++---+
+
+ This should output the following:
+
++---+
+Hello, World
++---+
+
+*Using <<prefix:mojo>> Invocation Syntax
+
+ Our new plugin works, but look at that command line... The next thing is to
+ configure Maven so we can use the familiar <<prefix:mojo>> invocation syntax,
+ and leave that verbose, fully-qualified mess behind.
+
+ As you know, Maven maps plugins to user-friendly prefixes. However, these
+ prefixes might overlap; that is, multiple plugins may try to use the same
+ prefix inadvertently. To avoid the obvious ambiguity associated with such
+ a collision, Maven will search a predetermined list of plugin groupIds for
+ a given prefix, with the first match winning. So, if we want to add our new
+ plugin to this search, we need to configure the list of plugin groupIds.
+
+**Configuring Plugin-Prefix Searching
+
+ In order to reference our new plugin by prefix, we need to add its groupId to
+ the <<<\<pluginGroups/\>>>> list in the <<<settings.xml>>> file. As you
probably
+ know, this file is usually found under $HOME/.m2. The added section to make
our
+ plugin's groupId searchable should look like this:
+
++---+
+~/.m2/settings.xml:
+------------------------------
+
+ <settings>
+ .
+ .
+ .
+ <pluginGroups>
+ <pluginGroup>org.myproject.plugins</pluginGroup>
+ </pluginGroups>
+ .
+ .
+ .
+ </settings>
++---+
+
+**Run It
+
+ We can check that this worked by invoking our new mojo once again, this time
+ using the prefix syntax:
+
++---+
+mvn hello:hello
++---+
+
+*Adding Plugin Parameters
+
+ Now, suppose it's not enough that our plugin display static text to the
console.
+ Suppose we need it to display a greeting that is a little more personalized.
+ We can easily add support for this by adding a <<name>> parameter. For good
measure,
+ we'll output the current project's name as well.
+
+**Change the Ant Script
+
+ The build script will have to change to output the new information:
+
++---+
+hello.build.xml:
+--------------------------------
+
+ <!-- The specification of the "hello" default target here allows us to
+ simplify the mapping document for a single mojo, as below.
+ -->
+ <project default="hello">
+ <target name="hello">
+ <echo>Hello, ${name}. You're building project: ${projectName}</echo>
+ </target>
+ </project>
++---+
+
+**Change the Mapping Document
+
+ Now that we have a build script which requires two new parameters, we have to
+ tell the mapping document about them, so they will be injected into the Ant
+ Project instance.
+
++---+
+hello.mojos.xml:
+------------------------------
+
+ <pluginMetadata>
+ <mojos>
+ <mojo>
+ <goal>hello</goal>
+ <requiresProject>true</requiresProject>
+
+ <description>
+ Say Hello, including the user's name, and print the project name to
the console.
+ </description>
+ <parameters>
+ <parameter>
+ <name>name</name>
+ <property>name</property>
+ <required>true</required>
+ <expression>${name}</expression>
+ <type>java.lang.String</type>
+ <description>The name of the user to greet.</description>
+ </parameter>
+
+ <parameter>
+ <name>projectName</name>
+ <property>projectName</property>
+ <required>true</required>
+ <readonly>true</readonly>
+ <defaultValue>${project.name}</defaultValue>
+ <type>java.lang.String</type>
+ <description>The name of the project currently being
built.</description>
+ </parameter>
+ </parameters>
+ </mojo>
+ </mojos>
+ </pluginMetadata>
++---+
+
+ You'll notice several differences from the old version of the mapping
document.
+ First, we've added <<requiresProject="true">> to the mojo declaration. This
tells
+ Maven that our mojo requires a valid project before it can execute...in our
case,
+ we need a project so we can determine the correct <<projectName>> to use.
Next,
+ we've added two parameter declarations to our mojo mapping; one for <<name>>
and
+ another for <<projectName>>.
+
+ The <<name>> parameter declaration provides an expression attribute...this
+ allows the user to specify <<<-Dname=somename>>> on the command line.
Otherwise,
+ the only way to configure this parameter would be through a
<<<\<configuration/\>>>>
+ element within the plugin specification in the user's POM. Note that this
+ parameter is required to have a value before our mojo can execute.
+
+ The <<projectName>> parameter declaration provides two other interesting
items.
+ First, it specifies a defaultValue attribute, which specifies an expression
to
+ be evaluated against Maven's current build state in order to extract the
parameter's
+ value. Second, it specifies a readonly attribute, which means the user cannot
+ directly configure this parameter - either via command line or configuration
+ within the POM. It can only be modified by modifying the build state
referenced
+ in the defaultValue...in our case, the name element of the POM. Also note
that
+ this parameter is declared to be required before our mojo can execute.
+
+**Rebuild It and Run It
+
+ Now that we've modified our plugin, we have to rebuild it before running it
again.
+
++---+
+mvn clean install
++---+
+
+ Next, we should run the plugin again to verify that it's doing what we
expect.
+ However, before we can run it, we have some requirements to satisfy. First,
we
+ have to be sure we're executing in the context of a valid Maven
POM...runnning
+ in the plugin's own project directory should satisfy that requirement. Then,
+ we have to satisfy the name requirement. We can do this directly through the
+ command line. So, the resulting invocation of our plugin will look like this:
+
++---+
+mvn -Dname=<your-name-here> hello:hello
++---+
+
+ or, in my case:
+
++---+
+mvn -Dname=John hello:hello
++---+
+
+ This should output the following:
+
++---+
+Hello, John. You're building project: Hello Plugin
++---+
+
+*Defining Multiple Mojos from One Build Script
+
+ If you're familiar with Ant, you're probably familiar with the common usage
+ pattern of defining multiple build types within a single build script. For
+ instance, you might have a build type for cleaning the project, another for
+ producing the application jar file, and yet another for producing the full
+ distribution including javadocs, etc.
+
+ The concept is pretty simple. Discrete chunks of the build process are
separated
+ into targets within the script. These targets can reference one another in
+ order to make reuse within the build script possible.
+
+ These same concepts map pretty well to Maven, actually. However, instead of
+ targets directly referencing one another, they would be bound to the
appropriate
+ phases of the build lifecycle. In this way, multiple Ant targets from the
same
+ build script can be reused piecemeal at different points in multiple build
+ lifecycles (clean, site, and the main lifecycle are three examples).
+
+ This section will describe how to map multiple logical mojos onto different
+ targets within the same Ant build script. It's also possible to reference
+ targets from multiple build scripts, but we'll cover this later.
+
+**Two Targets, One Script
+
+ To test this, we'll split our echo statement into two targets. Then,
+ we'll reference each as separate mojos in the build. The new script
+ looks like this:
+
++---+
+one-two.build.xml:
+--------------------------------
+
+ <!-- NOTE: The default target has been removed. This is no longer
+ needed, since we're going to use two independently mapped
+ mojos from this script.
+ -->
+ <project>
+ <target name="one">
+ <echo>Hello, ${name}.</echo>
+ </target>
+
+ <target name="two">
+ <echo>You're building project: ${projectName}</echo>
+ </target>
+ </project>
++---+
+
+**Map the Mojos
+
+ Next, we'll modify our original mapping document to map these two new mojos
+ instead of the old one:
+
++---+
+one-two.mojos.xml:
+------------------------------
+
+ <pluginMetadata>
+ <mojos>
+ <mojo>
+ <goal>one</goal>
+ <call>one</call>
+
+ <description>
+ Say Hello. Include the user's name.
+ </description>
+ <parameters>
+ <parameter>
+ <name>name</name>
+ <property>name</property>
+ <required>true</required>
+ <expression>${name}</expression>
+ <type>java.lang.String</type>
+ <description>The name of the user to greet.</description>
+ </parameter>
+ </parameters>
+ </mojo>
+
+ <mojo>
+ <goal>two</goal>
+ <call>two</call>
+ <requiresProject>true</requiresProject>
+
+ <description>
+ Write the project name to the console.
+ </description>
+ <parameters>
+ <parameter>
+ <name>projectName</name>
+ <property>projectName</property>
+ <required>true</required>
+ <readonly>true</readonly>
+ <defaultValue>${project.name}</defaultValue>
+ <type>java.lang.String</type>
+ <description>The name of the project currently being
built.</description>
+ </parameter>
+ </parameters>
+ </mojo>
+ </mojos>
+ </pluginMetadata>
++---+
+
+ Now that we've split the old functionality into two distinct mojos, there are
+ some interesting consequences. Aside from the obvious, mojo <<one>> no longer
+ requires a valid project instance in order to execute, since we only require
+ the user's name in order to greet him.
+
+ Aside from this, we've added a new <<\<call\>>> element for each mojo in the
+ mapping document. This element describes which Ant target should be called
+ when the mojo is invoked.
+
+**Build It, Run It
+
+ Now that we have two separate mojos, we can execute them singly, or in any
order
+ we choose. We can bind them to phases of the lifecycle using plugin
configuration
+ inside the build element of a POM. We can execute them like this:
+
++---+
+mvn -Dname=John hello:one
+
+RETURNS:
+
+Hello, John.
+
+
+mvn hello:two (executed in the plugin's project directory)
+
+RETURNS:
+
+You're building project: Hello Plugin
++---+
+
+ Alternatively, you could build a POM like this:
+
++---+
+test-project/pom.xml:
+----------------------------
+
+ <project>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.myproject.tests</groupId>
+ <artifactId>hello-plugin-tests</artifactId>
+ <version>1.0</version>
+
+ <name>Test Project</name>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.myproject.plugins</groupId>
+ <artifactId>hello-plugin</artifactId>
+
+ <configuration>
+ <name>John</name>
+ </configuration>
+
+ <executions>
+ <execution>
+ <phase>validate</phase>
+ <goals>
+ <goal>one</goal>
+ <goal>two</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </project>
++---+
+
+ Then, simply call Maven on this new POM:
+
++---+
+cd test-project
+mvn validate
++---+
+
+ You should see the following output:
+
++---+
+Hello, John.
+You're building project: Test Project
++---+
+
+**A Note on Multiple Build Scripts
+
+ It's worth mentioning that Ant-driven plugins can just as easily contain
+ multiple Ant build scripts. Simply follow the naming rules - naming each
+ A.build.xml, B.build.xml, C.build.xml, etc. for example - and be sure to
+ provide a mapping document to correspond to each build script that contains
+ a mojo (other build scripts may be contained in the plugin, and referenced
+ by one of these; they don't need mapping documents). So, for the above
examples
+ (assuming they all contained mojo targets), you'd need: A.mojos.xml,
B.mojos.xml,
+ and C.mojos.xml. If C.build.xml was referenced by A and B, but didn't contain
+ mojo targets, then you don't need a C.mojos.xml for obvious reasons.
+
+*Advanced Usage
+
+ Below are some tips on some of the more advanced options related to Ant
mojos.
+
+**Component References
+
+ If your plugin needs a reference to a Plexus component, it will have to
define
+ something similar to the following in the mapping document:
+
++---+
+ <pluginMetadata>
+ <mojos>
+ <mojo>
+ .
+ .
+ .
+ <components>
+ <component>
+ <role>org.apache.maven.project.MavenProjectBuilder</role>
+ <hint>default</hint> <!-- This is optional -->
+ </component>
+ </components>
+ .
+ .
+ .
+ </mojo>
+ </mojos>
+ </pluginMetadata>
++---+
+
+**Forking New Lifecycles
+
+ In case your plugin needs to fork a new lifecycle, you can include the
+ following in the mapping document:
+
++---+
+ <pluginMetadata>
+ <mojos>
+ <mojo>
+ .
+ .
+ .
+ <execute>
+ <lifecycle>my-custom-lifecycle</lifecycle>
+ <phase>package</phase>
+
+ <!-- OR -->
+
+ <goal>some:goal</goal>
+ </execute>
+ .
+ .
+ .
+ </mojo>
+ </mojos>
+ </pluginMetadata>
++---+
+
+**Deprecation
+
+ As time goes on, you will likely have to deprecate part of your plugin.
+ Whether it's a mojo parameter, or even an entire mojo, Maven can support
+ it, and remind your users that the mojo or configuration they're using is
+ deprecated, and print a message directing them to adjust their usage.
+
+ To deprecate a mojo parameter, simply add this:
+
++---+
+ <pluginMetadata>
+ <mojos>
+ <mojo>
+ .
+ .
+ .
+ <parameters>
+ <parameter>
+ .
+ .
+ .
+ <deprecated>Use this other parameter instead.</deprecated>
+ .
+ .
+ .
+ </parameter>
+ </parameters>
+ .
+ .
+ .
+ </mojo>
+ </mojos>
+ </pluginMetadata>
++---+
+
+ To deprecate an entire mojo, add this:
+
++---+
+ <pluginMetadata>
+ <mojos>
+ <mojo>
+ .
+ .
+ .
+ <deprecated>Use this other mojo instead.</deprecated>
+ .
+ .
+ .
+ </mojo>
+ </mojos>
+ </pluginMetadata>
++---+
Propchange:
maven/site/trunk/src/site/apt/guides/plugin/guide-ant-plugin-development.apt
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
maven/site/trunk/src/site/apt/guides/plugin/guide-ant-plugin-development.apt
------------------------------------------------------------------------------
svn:keywords = "Author Date Id Revision"
Modified:
maven/site/trunk/src/site/apt/guides/plugin/guide-java-plugin-development.apt
URL:
http://svn.apache.org/viewcvs/maven/site/trunk/src/site/apt/guides/plugin/guide-java-plugin-development.apt?rev=367925&r1=367924&r2=367925&view=diff
==============================================================================
---
maven/site/trunk/src/site/apt/guides/plugin/guide-java-plugin-development.apt
(original)
+++
maven/site/trunk/src/site/apt/guides/plugin/guide-java-plugin-development.apt
Tue Jan 10 20:58:12 2006
@@ -167,15 +167,25 @@
*** Shortening the Command Line
- It is possible to shorten the amount of typing needed on the command
- line. To do this, you need to install the plugin with the
- <<<updateReleaseInfo>>> option set to true; for example:
+~~ [jdcasey; 10-Jan-2006]
+~~
+~~ I'm commenting this out, since it's obsolete. The plugin version
+~~ manager now checks LATEST metadata before it checks RELEASE metadata.
+~~ Since LATEST metadata is _always_ published for plugins, nothing
+~~ special needs to be done for the prefix matching to work.
+~~
+~~ It is possible to shorten the amount of typing needed on the command
+~~ line. To do this, you need to install the plugin with the
+~~ <<<updateReleaseInfo>>> option set to true; for example:
+~~
+~~ +----+
+~~ mvn -DupdateReleaseInfo=true install
+~~ +----+
+~~
+~~ You also need to add your plugin's group ID to the list of group IDs
-+----+
-mvn -DupdateReleaseInfo=true install
-+----+
-
- You also need to add your plugin's group ID to the list of group IDs
+ In order to shorten the amount of typing needed on the command line,
+ you will need to add your plugin's group ID to the list of group IDs
searched by default. To do this, you need to add the following to
your <<<settings.xml>>> file: