Hari Kodungallur wrote:

> I am new to Maven. [...] Each module has an ant build file. I also
> have a master build file which is used to build all the modules,
> mainly during nightly build. [..] We don't want to move away from
> individual module ant build files. We would like to use Maven to
> manage all the individual ant build files (as a master build file,
> sort of) and in addition use the plug-ins available for the other
> tools to do code coverage and code checking for all modules.

I'm fairly new to maven too, but had similar issues to begin
with. Whats below is just what I did.

> (1)	Is Maven the right tool to do this?

Not if you want to keep the individual ant build files. Maven gives
you the most benefit if you are willing to stick to the maven
directory layout, and only write a project.xml - there gives you the
least to maintain in each module. If you try to keep a different
directory structure and list of targets from maven's you'll find
its like swimming uphill.

The question you need to answer is, why do you want to keep the ant
files? If each project is truly different you can just add some of
your ant tasks into the project's maven.xml; the only other reasons
we have for keeping ant are that maven is still beta, and the level
of IDE integration from maven, though we're happier with this now[1]

Going back to your 'master' build file - you seem to be using it both
to provide a common set of goals/targets to projects, and to execute
that common set of goals from a nightly build.  I think those two
functions would be better separated, into a file you 'include' from
all your ant scripts, and a simpler 'master' script that just does the
checkout-build-label cycle for nightlies. Have you read 'Ant in
Anger'[2]? You could possibly even ditch the 'nightly' aspect in
favour of a tool like anthill[3], CruiseControl[4], or the Gump[5].

If you went with maven, it takes the role of the included file -
giving you access to all of maven's plugins from all of your projects
- and the 'reactor'[6] is the thing that does 'master' builds.

> (2)	If yes, can somebody give me some HOWTOs and also sample project
> descriptors to do this kind of tasks? Anything closely related will be
> very helpful, as either the documentation on Maven's website is too
> little or too confusing to me.

Since I'm in the position of having some ant projects and some maven
projects I want to build nightly (until we make the jump to maven
only) I looked into setting up various tools to do the
automated/nightly builds. As we're not on CVS, the Gump was out of the
question for us; so I went with Anthill, and wrote an anthill-build.xml
(attached) that I use for /all/ maven projects - it just executes
a couple of maven goals. Its not ideal, but it lets me work with ant
and maven side by side.

One caveat, there is a bug in maven preventing it returning an exit
code[7], so anthill won't detect build failures; I had to patch my
copy to fix this.

An alternative approach I tried was to write an ant script to do maven
and/or ant builds in a similar manner to anthill. The idea was to
write a multiproject build script which simply cycles over the
projects to build, and for each calls a single project 'bootstrap'
checkout-build-label script (attached), which in turn calls the
project's actual build file via the correct tool. The attached script
is again aimed at working with building ant and maven projects side
by side, and doesn't address the issue of sharing targets between
ant scripts.

However I should point out that I consider all of these to be sticking
plaster approaches - I want to move /all/ of our projects across to
maven as, despite its flaws, it is a vast improvement!

-Baz
>
> Thank you very much
> -Hari
>

[1] To integrate an IDE with a build tool, you mainly need the ability
to parse error output, and for advanced features, access to the same
classpath for code completion etc. Running maven with '-E' presents
unadorned javac error messages, I've successfully worked with maven
under XEmacs and netbeans by using just the error output; apparently
integration with Eclipse and IntelliJ IDEA is even better.
[2]http://jakarta.apache.org/ant/ant_in_anger.html
[3]http://www.urbancode.com/projects/anthill/default.jsp
[4]http://cruisecontrol.sourceforge.net/
[5]http://jakarta.apache.org/gump/
[6]http://jakarta.apache.org/turbine/maven/reference/user-guide.html#Multi%20Project%20Builds
[7]http://jira.werken.com/secure/ViewIssue.jspa?key=FOREHEAD-3
<?xml version="1.0" encoding="UTF-8"?>

<project default="maven" name="mavenized" basedir=".">
  
<property environment="env"/>
<property name="env.MAVEN_HOME" value="C:\Program Files\Maven"/>
<property name="maven.goal" value="jar:install"/>
<property name="maven.project" value="MAVEN_PROJECT_NOT_SET"/>
<property name="maven.dir" value="${basedir}\work\${maven.project}"/>

<target name="maven" >
    <echo message="Using MAVEN_HOME=${env.MAVEN_HOME} ${version}"/>
    <java classname="com.werken.forehead.Forehead" fork="yes" maxmemory="128m">
        <arg value="-d" />
        <arg value="${maven.dir}" />
        <arg value="${maven.goal}" />
        <classpath>
            <pathelement location="${env.MAVEN_HOME}\lib\forehead-1.0-beta-4.jar" />
        </classpath>
        <sysproperty key="maven.home" value="${env.MAVEN_HOME}" />
        <sysproperty key="tools.jar" value="${env.JAVA_HOME}\lib\tools.jar" />
        <sysproperty key="forehead.conf.file" value="${env.MAVEN_HOME}\bin\forehead.conf" />
        <sysproperty key="maven.site.deploy.method" value="fs"/>
        <sysproperty key="pom.siteDirectory" value="${deployDir}"/>
        <sysproperty key="project.siteDirectory" value="${deployDir}"/>
        <sysproperty key="project.currentVersion" value="${version}"/>
        <sysproperty key="pom.currentVersion" value="${version}"/>
        <sysproperty key="maven.final.name" value="${maven.project}-${version}"/>
    </java>
</target>

</project>
    
<?xml version="1.0" standalone="yes"?>
<project name="nightlies" default="all" basedir=".">

  <!-- ==============================================================
  Check if the build is required, then build. The build.timestamp file
  will be updated to indicate success if the build works.  
  ================================================================ -->
  <target name="all" depends="check-build-required, build-status, build">
    <echo message="SUCCESS at ${START_TIME}" 
	  append="false" file="${build.timestamp}"/>
  </target>
  
  <!-- ==============================================================
  Sets up properties we need for the build, and creates some
  directories that will be used later.
  ================================================================ -->
  <target name="prepare">
    <fail message="Project not specified!" unless="project"/>
    <property name="/" value="${file.separator}"/>

    <mkdir dir="properties"/>
    <property name="project.properties" 
	      value="properties/${project}.properties"/>
    <available file="${project.properties}"
	       property="project.properties.available"/>
    <fail message="Cannot find project properties ${project.properties}" 
	  unless="project.properties.available"/>
    <property file="${project.properties}"/>

    <fail message="Project SCM repository not configured" unless="project.scm"/>
    <!-- set up scm functions. 'init-(scm)' should check if its configured ok. -->
    <antcall target="init-${project.scm}"/>
    <property name="scm.get.target" value="get-with-${project.scm}"/>
    <property name="scm.checkout.target" value="checkout-with-${project.scm}"/>
    <property name="scm.checkin.target" value="checkin-with-${project.scm}"/>
    <property name="scm.label.target" value="label-with-${project.scm}"/>

    <!-- fail early, fail often... -->
    <fail message="Build system not set!" unless="project.build.system"/>
    <fail message="Build file not set!" unless="project.build.file"/>
    <fail message="Build target not set!" unless="project.build.target"/>
    <fail message="Publish target not set!" unless="project.publish.target"/>
    <fail message="Project build number file not set!"
          unless="project.build.number"/>

    <property name="build.work.dir" value="work/${project}"/>
    <property name="publish.dir" value="${basedir}${/}projects${/}${project}"/>
    <mkdir dir="${publish.dir}"/>
    <tstamp>
      <format property="START_TIME" pattern="EEE, d MMM yyyy HH:mm:ss Z"/>
    </tstamp>
    <property name="build.timestamp" 
	      value="${publish.dir}/build.timestamp"/>
  </target>

  <!-- ==============================================================
  Fetch updates to current version, and check if the project is up to
  date. This is faster than always getting a clean version every time,
  but will not spot deletions on systems that don't work that way.
  Also, it doesn't require parsing of tool messages!
  ================================================================ -->
  <target name="check-build-required" depends="prepare"
	  unless="build.forced">
    <antcall target="${scm.get.target}"/>
    <uptodate property="build.uptodate" targetfile="${build.timestamp}">
      <srcfiles dir="${build.work.dir}"/>
    </uptodate>
  </target>

  <!-- ==============================================================
  Writes a message into the log if the build wasnt required.
  ================================================================ -->
  <target name="build-status" if="build.uptodate">
    <echo message="${project} is up to date."/>
  </target>

  <!-- ==============================================================
  Build the project with the appropriate build system, if required.
  ================================================================ -->
  <target name="build" unless="build.uptodate">
    <!-- timestamp file contains a failure message unless it
    gets overwritten. This could be displayed to the user. -->
    <echo message="FAILED at ${START_TIME}" append="false" 
	  file="${build.timestamp}"/>

    <echo message="Getting clean copy of ${project}"/> 
    <delete dir="${build.work.dir}" failonerror="false" quiet="true"/>
    <antcall target="${scm.get.target}"/>

    <!-- number the build -->
    <property name="build.number.file"
	      value="${build.work.dir}${/}${project.build.number}"/>
    <available file="${build.number.file}"
	       property="build.number.file.available"/>
    <fail message="Cannot read build number file ${project.build.number}"
          unless="build.number.file.available"/>
    <antcall target="${scm.checkout.target}"/>
    <buildnumber file="${build.number.file}"/>
    <echo message="Set build number to ${build.number}"/>
    <echo message="Checking in build number for ${project}"/>
    <antcall target="${scm.checkin.target}" />

    <!-- set up logs (based on build numbers) -->
    <property name="log.dir" value="${publish.dir}${/}logs"/>
    <mkdir dir="${log.dir}"/>
    <property name="build.log" 
	      value="${log.dir}${/}build-${build.number}.log"/>
    <property name="publish.log" 
	      value="${log.dir}${/}publish-${build.number}.log"/>
    
    <!-- build the project -->
    <antcall target="build-with-${project.build.system}">
      <param name="param.log" value="${build.log}"/>
      <param name="param.target" value="${project.build.target}"/>
    </antcall>
    <antcall target="${scm.label.target}">
      <param name="scm.label" value="${project}-build-${build.number}"/>
    </antcall>
    <antcall target="build-with-${project.build.system}">
      <param name="param.log" value="${publish.log}"/>
      <param name="param.target" value="${project.publish.target}"/>
    </antcall>
  </target>

  <!-- ==============================================================
  Build a project goal using maven.
  ================================================================ -->
  <target name="build-with-maven">
    <fail message="maven.home not set!" unless="maven.home"/>
    <echo message="Calling maven ${project.build.file} ${param.target}"/>
    <java classname="com.werken.forehead.Forehead" 
	  failonerror="true" fork="true" maxmemory="128m"
	  dir="${build.work.dir}" output="${param.log}"
	  timeout="600000">
      <arg value="-p"/>
      <arg value="${project.build.file}"/>
      <arg value="${param.target}" />        
      <classpath>
	<fileset dir="${maven.home}${/}lib">
	  <include name="forehead*.jar"/>
	</fileset>
      </classpath>
      <sysproperty key="maven.home" value="${maven.home}" />
      <sysproperty key="tools.jar" 
		   value="${java.home}${/}..${/}lib${/}tools.jar" />
      <sysproperty key="forehead.conf.file" 
		   value="${maven.home}${/}bin${/}forehead.conf" />
      <sysproperty key="maven.site.deploy.method" value="fs"/>
      <sysproperty key="project.siteDirectory" value="${publish.dir}"/>
    </java>
  </target>

  <!-- ==============================================================
  Execute a project target using ant. 
  ================================================================ -->
  <target name="build-with-ant">
    <echo message="Calling ant ${build.work.dir} ${project.build.file} ${param.target}"/>
    <java classname="org.apache.tools.ant.Main"
	  failonerror="true" fork="true" maxmemory="128m"
	  dir="${build.work.dir}" output="${param.log}"
	  timeout="600000">
      <arg value="-buildfile"/>
      <arg value="${project.build.file}"/>
      <arg value="${param.target}" />
      <classpath>
	<fileset dir="lib">
	  <include name="*.jar"/>
	</fileset>
      </classpath>
      <sysproperty key="build.number" value="${build.number}" />
      <sysproperty key="publish.dir" value="${publish.dir}" />
    </java>
  </target>

  <!-- ==============================================================
  Get rid of any artifacts, logs, timestamps etc created by building
  projects.
  ================================================================ -->
  <target name="clean">
    <delete dir="work"/>
    <delete dir="projects"/>
  </target>

  <!-- ==============================================================
  SCM faked using the filesystem, useful for testing. 
  ================================================================ -->
  <target name="init-fs">
    <fail message="Path to FS repository not set!"
	  unless="project.fs.repository"/>
  </target>
  <target name="get-with-fs">
    <copy todir="${build.work.dir}" preservelastmodified="true">
      <fileset dir="${project.fs.repository}"/>
    </copy>
  </target>
  <target name="checkout-with-fs">
    <copy todir="${build.work.dir}" 
	  file="${project.fs.repository}${/}${project.build.number}"/>
    <!-- should really do chmod, but I am testing on windoze -->
  </target>
  <target name="checkin-with-fs">
    <copy todir="${project.fs.repository}" 
	  file="${build.work.dir}${/}${project.build.number}"/>
  </target>
  <target name="label-with-fs">
    <echo message="${scm.label}" append="false" 
	  file="${project.fs.repository}${/}LABEL"/> 
  </target>

  <!-- ==============================================================
  SCM support for Microsoft VSS. Equivalent of anthill's VSS adapter.
  ================================================================ -->
  <!-- I am testing at home using 'fs' instead of vss. This stuff
  matches the docs but may be wrong -->
  <target name="init-vss">
    <fail message="Path to ss.exe not set!" unless="vss.path"/>
    <fail message="VSS module not set!" unless="project.vss.module"/>
    <fail message="VSS login not set!" unless="project.vss.login"/>
    <fail message="Path to VSS repository (SSDIR) not set!"
	  unless="project.vss.repository"/>
  </target>
  <!-- documentation has MS's definition of ssdir and serverPath reversed. 
  need to suck this and see... -->
  <target name="get-with-vss">
    <vssget vsspath="${project.vss.module}"
	    login="${project.vss.login}"
	    ssdir="${vss.path}" recursive="true"
	    serverPath="${project.vss.repository}"/>
  </target>
  <target name="checkout-with-vss">
    <vssget vsspath="${project.vss.module}\${project.build.number}"
              login="${project.vss.login}" ssdir="${vss.path}"
              serverPath="${project.vss.repository}"/>
  </target>
  <target name="checkin-with-vss">
    <vssget vsspath="${project.vss.module}\${project.build.number}"
              login="${project.vss.login}" ssdir="${vss.path}"
              serverPath="${project.vss.repository}"/>
  </target>
  <target name="label-with-vss">
    <vsslabel vsspath="${project.vss.module}"
              login="${project.vss.login}"
              ssdir="${vss.path}" label="${scm.label}" 
              serverPath="${project.vss.repository}"/>
  </target>
</project>

--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to