Much ado about scripting, Linux & Eclipse: card subject to change

Showing posts with label ant-contrib. Show all posts
Showing posts with label ant-contrib. Show all posts

2011-10-26

HOWTO: Use Maven, Ant, and XSLT to scrub unwanted p2 metadata from an update site

Some time ago, I wrote about Using p2.inf to add/remove update sites. Tonight I found a simpler way to remove references in p2 metadata to external 3rd party sites.

For example, say you're repackaging some 3rd party features onto your own site, but don't want those features to provide references to the vendor's own update sites because you want to ensure that your product's site will only result in your sanctioned version being installed.

When you generate an update site, p2 pulls the information in the included features and will result in a section of references in the site's metadata that looks like this:

  <references size="6">
    <repository uri="http://download.eclipse.org/egit/updates" url="http://download.eclipse.org/egit/updates" type="0" options="0"/>
    <repository uri="http://subclipse.tigris.org/update_1.6.x" url="http://subclipse.tigris.org/update_1.6.x" type="1" options="0"/>
    <repository uri="http://download.eclipse.org/egit/updates" url="http://download.eclipse.org/egit/updates" type="1" options="0"/>
    <repository uri="http://subclipse.tigris.org/update_1.6.x" url="http://subclipse.tigris.org/update_1.6.x" type="0" options="0"/>
    <repository uri="http://eclipse.svnkit.com/1.3.x/" url="http://eclipse.svnkit.com/1.3.x/" type="0" options="0"/>
    <repository uri="http://eclipse.svnkit.com/1.3.x/" url="http://eclipse.svnkit.com/1.3.x/" type="1" options="0"/>
  </references>
To remove that, you can play with p2.inf directives, or you can simply perform an XSL transformation on the generated content.xml (inside content.jar, if your metadata is compressed) to remove the <references/> node:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:template match="/">
        <xsl:apply-templates select="*"/>
</xsl:template>
<xsl:template match="*">
        <xsl:copy >
                <xsl:for-each select="@*">
                        <xsl:copy />
                </xsl:for-each>
                <xsl:apply-templates />
        </xsl:copy>
</xsl:template>
<xsl:template match="references" />
</xsl:stylesheet>
If you're generating your update site w/ Tycho, this transform can be called via a simple Ant script:

       <target name="remove.references">
                <!-- requires ant-contrib only if you like using if-then-else structures -->
                <if>
                        <available file="${update.site.source.dir}/content.jar" type="file" />
                        <then>
                                <unzip src="${update.site.source.dir}/content.jar" dest="${update.site.source.dir}" />
                                <delete file="${update.site.source.dir}/content.jar" />
                        </then>
                </if>
                <copy file="${update.site.source.dir}/content.xml" tofile="${update.site.source.dir}/content.old.xml" overwrite="true" />
                <xslt style="remove-references.xsl" in="${update.site.source.dir}/content.old.xml" out="${update.site.source.dir}/content.xml" />
                <zip destfile="${update.site.source.dir}/content.jar" basedir="${update.site.source.dir}" includes="content.xml" />
                <delete file="${update.site.source.dir}/content.xml" />
                <delete file="${update.site.source.dir}/content.old.xml" />
        </target>

Then, in your site's pom.xml, to call the Ant script, do this:

       <build>
                <plugins>
                        <plugin>
                                <groupId>org.apache.maven.plugins</groupId>
                                <artifactId>maven-antrun-plugin</artifactId>
                                <!-- make sure this variable is defined, eg., set to 1.3 -->
                                <version>${maven.antrun.plugin.version}</version>
                                <executions>
                                        <execution>
                                                <id>install</id>
                                                <phase>install</phase>
                                                <configuration>
                                                        <quiet>true</quiet>
                                                        <tasks>
                                                                <!-- called AFTER generating update site + zip to tweak content -->
                                                                <ant antfile="build.xml">
                                                                        <property name="SOME_ANT_VARIABLE" value="${SOME_MAVEN_VARIABLE}" />
                                                                </ant>
                                                        </tasks>
                                                </configuration>
                                                <goals>
                                                        <goal>run</goal>
                                                </goals>
                                        </execution>
                                </executions>
                                <dependencies>
                                        <!-- some dependencies your ant script might need -->
                                        <dependency>
                                                <groupId>commons-net</groupId>
                                                <artifactId>commons-net</artifactId>
                                                <version>1.4.1</version>
                                        </dependency>
                                        <dependency>
                                                <groupId>org.apache.ant</groupId>
                                                <artifactId>ant</artifactId>
                                                <version>1.7.1</version>
                                        </dependency>
                                        <dependency>
                                                <groupId>org.apache.ant</groupId>
                                                <artifactId>ant-nodeps</artifactId>
                                                <version>1.7.1</version>
                                        </dependency>
                                        <dependency>
                                                <groupId>org.apache.ant</groupId>
                                                <artifactId>ant-trax</artifactId>
                                                <version>1.7.1</version>
                                        </dependency>
                                        <dependency>
                                                <groupId>org.apache.ant</groupId>
                                                <artifactId>ant-commons-net</artifactId>
                                                <version>1.7.1</version>
                                        </dependency>
                                        <dependency>
                                                <groupId>org.apache.ant</groupId>
                                                <artifactId>ant-apache-regexp</artifactId>
                                                <version>1.7.1</version>
                                        </dependency>
                                        <dependency>
                                                <groupId>ant-contrib</groupId>
                                                <artifactId>ant-contrib</artifactId>
                                                <version>1.0b3</version>
                                        </dependency>
                                </dependencies>
                        </plugin>
                </plugins>
        </build>

I suppose there's probably a way to call a transform directly from Maven w/o the Ant wrapper, but this allows unpacking and repacking of the content.jar to get at the content.xml file.

2010-06-30

Update Site Aggregation: B3 vs. Tycho

Last year, I used to aggregate update sites with the Buckminster Aggregator, but since that won't install into Eclipse 3.6 (Helios), I had to migrate to the B3 Aggregator. This new version of the Aggregator is greatly expanded and worked fine until recently, when it has begun to suffer from a rather nasty p2 problem: instead of the Director just installing the aggregator into an Eclipse instance prior to then running the aggregation, I get "The copies of profile SDKProfile are not in sync," and the whole process dies. http://www.blogger.com/img/blank.gif

So, in order to find a workaround, I went back to Tycho, and discovered you can merge update sites with little more than two simple files:

  • a site.xml, which lists the features to aggregate and how to categorize them, and
  • a pom.xml to list the source sites and drive the aggregation.

Unfortunately the Tycho solution doesn't include the ability to add associate sites to the metadata after generation, but that can simply be done as a downstream step (Tycho can call Ant using the maven-antrun-plugin).

2010-04-04

Cleaner Ant Build Logs: Get Rid of "Trying to override old definition of task"

If you use macros in Ant, you have probably seen clutter in your log such as

Trying to override old definition of task ...

Here's how to purge this garbage from your log and keep your build output cleaner.

  1. move your macros into a target such as <target name="init">
  2. have your main target(s) depend on the target that defines the macros
  3. call your macros

You can make your log even quieter with -q when running ant, eg., ant -f build.xml -q

Here's a complete example that will first self-bootstrap itself by downloading Ant-Contrib, define two ant macros, and produce very quiet output (unless debug=true):

<project default="run">
 <property name="COMMON_TOOLS" value="${java.io.tmpdir}" />
 <property name="debug" value="false"/>

 <target name="get.ant-contrib" unless="ant-contrib.jar.exists">
  <property name="ANTCONTRIB_MIRROR" value="http://downloads.sourceforge.net/ant-contrib/" />
  <get usetimestamp="true"
       dest="${COMMON_TOOLS}/ant-contrib-1.0b2-bin.zip"
       src="${ANTCONTRIB_MIRROR}/ant-contrib-1.0b2-bin.zip"
  />
  <touch file="${COMMON_TOOLS}/ant-contrib-1.0b2-bin.zip" />
  <mkdir dir="${java.io.tmpdir}/ant-contrib-1.0b2-bin.zip_" />
  <unzip src="${COMMON_TOOLS}/ant-contrib-1.0b2-bin.zip"
         dest="${java.io.tmpdir}/ant-contrib-1.0b2-bin.zip_"
         overwrite="true"
  />
  <copy file="${java.io.tmpdir}/ant-contrib-1.0b2-bin.zip_/ant-contrib/lib/ant-contrib.jar"
        tofile="${COMMON_TOOLS}/ant-contrib.jar"
        failonerror="true"
  />
  <delete dir="${java.io.tmpdir}/ant-contrib-1.0b2-bin.zip_" includeemptydirs="true" quiet="true" />
 </target>

 <target name="init">
  <available file="${COMMON_TOOLS}/ant-contrib.jar" type="file" property="ant-contrib.jar.exists" />
  <antcall target="get.ant-contrib" />

  <taskdef resource="net/sf/antcontrib/antlib.xml">
   <classpath>
    <pathelement location="${COMMON_TOOLS}/ant-contrib.jar" />
   </classpath>
  </taskdef>
  
  <macrodef name="debug">
   <text name="echo" />
   <sequential>
    <if>
     <and>
      <isset property="debug" />
      <istrue value="${debug}" />
     </and>
     <then>
      <echo message="@{echo}" />
     </then>
    </if>
   </sequential>
  </macrodef>

  <macrodef name="list.count">
   <attribute name="list" default="" />
   <sequential>
    <var name="count" value="" />
    <for param="listitem" list="@{list}" delimiter=", ">
     <sequential>
      <var name="count" value="${count}0" />
     </sequential>
    </for>
    <length property="list.count.return" string="${count}" />
   </sequential>
  </macrodef>
 </target>

 <target name="run" depends="init">
  <property name="list" value="foo bar baz"/>
  <list.count list="${list}" />
  <debug>For list [${list}], size = </debug>
  <echo>${list.count.return}</echo>
 </target>

</project>