Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>I've worked out a solution that creates a jar file containing our reusable build scripts in a directory, say com/example/ant/sharedbuild, which can be imported in Ant 1.8:</p> <pre><code>&lt;project&gt; &lt;import&gt; &lt;javaresource name="com/example/ant/sharedbuild/java.xml"&gt; &lt;classpath location="../../../../target/ant-shared-build.jar" /&gt; &lt;/javaresource&gt; &lt;/import&gt; &lt;/project&gt; </code></pre> <p>In my case this defines all of the "public" targets for the project to do a java-based build.</p> <p>The syntax is a little verbose, especially as I add more and more include files (say, to add the ability to create an OSGi jar). By adding an antlib.xml that contains a combination of a macrodef and scriptdef to the jar file (in the same directory as the shared build scripts), the build file can now look like this (and now also creating an OSGi jar bundle):</p> <pre><code>&lt;project xmlns:build="antlib:com.example.ant.sharedbuild"&gt; &lt;taskdef uri="antlib:com.example.ant.sharedbuild" classpath="../../../../target/ant-shared-build.jar" /&gt; &lt;build:build using="java, jar, bundle" /&gt; &lt;/project&gt; </code></pre> <p>Unfortunately, I can't share the code in the macrodef or scriptdef, but really it isn't hard: a little javascript to parse the using attribute and loop over each, derive a file name from it, and import.</p> <p>I reference the jar file in a fixed location (relative to my project) on my hard drive. I think we can do better. Ideally, I'd like to fetch a (versioned!) jar file from a central location. Since we're already using Ivy (with an HTTP repository) we can publish the jar file there (again, with a version) and fetch it directly from there:</p> <pre><code>&lt;project xmlns:build="antlib:com.example.ant.sharedbuild"&gt; &lt;property name="ant.shared.build.jar.file" location="${user.home}/ant/ant-shared-build-1.5.3.jar" /&gt; &lt;get src="http://repo.example.com/.../ant-shared-build-1.5.3.jar" dest="${ant.shared.build.jar.file}" skipexisting="true" /&gt; &lt;taskdef uri="antlib:com.example.ant.sharedbuild" classpath="${ant.shared.build.jar.file}" /&gt; &lt;build:build using="java, jar, bundle" /&gt; &lt;/project&gt; </code></pre> <p>There are some problems with this:</p> <ol> <li>It's getting verbose again.</li> <li>The verbosity is repeated for every build.xml.</li> <li>There's a lot of repeated boilerplate, especially the version number.</li> </ol> <p>To mitigate these problems, in each directory containing a build.xml I also have a bootstrap.xml (the name doesn't really matter). Each build.xml then includes this file:</p> <pre><code>&lt;project xmlns:build="antlib:com.example.ant.sharedbuild"&gt; &lt;include file="bootstrap.xml" /&gt; &lt;build:build using="java, jar, bundle" /&gt; &lt;/project&gt; </code></pre> <p>Each bootstrap.xml, at a minimum, includes it's parent's bootstrap.xml:</p> <pre><code>&lt;project&gt; &lt;include file="../bootstrap.xml" /&gt; &lt;/project&gt; </code></pre> <p>The top-level bootstrap.xml (the root), then does the work of getting the jar file and creating the custom tasks, as above:</p> <pre><code>&lt;project&gt; &lt;property name="ant.shared.build.version" value="1.5.3" /&gt; &lt;property name="ant.shared.build.jar.filename" value="ant-shared-build-${ant.shared.build.version}.jar" /&gt; &lt;property name="ant.shared.build.jar.file" location="${user.home}/ant/${ant.shared.build.jar.filename}" /&gt; &lt;get src="http://repo.example.com/.../${ant.shared.build.jar.filename}" dest="${ant.shared.build.jar.file}" skipexisting="true" /&gt; &lt;taskdef uri="antlib:com.example.ant.sharedbuild" classpath="${ant.shared.build.jar.file}" /&gt; &lt;/project&gt; </code></pre> <p>Though not directly related to the question, I'm actually reworking the macrodef and scriptdef into a custom ant task, because I want to be able to support a syntax that looks like this:</p> <pre><code>&lt;project xmlns:build="antlib:com.example.ant.sharedbuild"&gt; &lt;include file="bootstrap.xml" /&gt; &lt;build:build&gt; &lt;using&gt; &lt;java /&gt; &lt;bundle&gt; &lt;manifest&gt; Import-Package: *,org.joda.time;version="[1.6.0,1.6.0]" Bundle-Activator: com.example.time.impl.Activator &lt;/manifest&gt; &lt;/bundle&gt; &lt;/using&gt; &lt;/build:build&gt; &lt;/project&gt; </code></pre> <p>I should point out that just creating a redistributable build doesn't mean it's going to be useful. You still need to put in the time and effort to create a cohesive, modular, consistent implementation in line with a design of similar characteristics. This is more important as you need to share scripts across projects, across teams, across organizational boundaries, etc.</p> <p>In conclusion, by creating a jar file, with a version number, that can be distributed independent of a specific file location or an SCM tool we can get real shared but reproducible builds.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload