2011年6月27日月曜日

Apache AntのインストーラーをApache Antでビルドする (その2)

久しぶりに時間が取れたので、先日の続きに取り組んでみる。ビルドプロセスをスクリプト化するところまではできたので、あとはインストール定義ファイルの加工処理を組み込めば完了、なはず。

DOCTYPE宣言の除去にXSLTを使う

やるべきことは、インストール定義ファイルからDOCTYPE宣言を除去すること。実現方法はいろいろありそうだが、

  • XMLファイルをテキストファイルとして処理するのはちょっと……
  • XML文書を加工するならXSLTでしょ

ということで、XSLTを使うことにした。

フォルダ構成

これまでインストール定義ファイルをプロジェクトフォルダのルートに格納していたが、これを機にsrc/installerに移す。このインストール定義ファイルがbuild/installerに複製/加工され、それをコンパイルすることでインストーラーが生成される。

2011-06-27/
  +-- build.xml
  +-- standalone.xsl      // DOCTYPE宣言を除去するためのXSLTスタイルシート
  +-- src/
  |     +-- installer/    // ここにインストール定義ファイルを格納しておく
  |           +-- install.xml
  |           +-- registry-spec.xml
  +-- build/
  |     +-- dist/
  |     +-- installer/    // ここにインストール定義ファイルが複製/加工される
  |           +-- install.xml
  |           +-- registry-spec.xml
  +-- target/
        +-- dist/
        +-- installer/

ビルドスクリプト (build.xml)

ビルドスクリプトは、先日作ったものを一部手直しして使う。具体的には下記のとおり。

  • 非公開ターゲットinstaller.buildを追加した。このターゲットは、インストール定義ファイルの複製/加工を行う。
  • izpack:compileタスク呼び出しを修正した。これまではプロジェクトフォルダのルートを起点としていたが、これをbuild/installerを起点とするよう変更した。
build.xml
<?xml version="1.0" encoding="UTF-8"?>

<project name="Apache Ant"
  default="installer"
  basedir="."
  xmlns:izpack="com.izforge.izpack">

  <!--==== Properties ======================================================-->

  <property environment="env"/>

  <property name="dist.name"
    value="apache-ant-1.8.2"/>

  <property name="src.dir"
    location="./src/"/>
  <property name="build.dir"
    location="./build/"/>
  <property name="target.dir"
    location="./target/"/>

  <property name="dist.build.dir"
    location="${build.dir}/dist/"/>
  <property name="dist.target.dir"
    location="${target.dir}/dist/"/>
  <property name="installer.src.dir"
    location="${src.dir}/installer/"/>
  <property name="installer.build.dir"
    location="${build.dir}/installer/"/>
  <property name="installer.target.dir"
    location="${target.dir}/installer/"/>

  <!--==== Task definitions ================================================-->

  <taskdef name="compile" uri="com.izforge.izpack"
    description="インストール定義ファイルをコンパイルします。"
    classname="com.izforge.izpack.ant.IzPackTask">
    <classpath>
      <pathelement location="${env.IZPACK_HOME}/lib/standalone-compiler.jar"/>
    </classpath>
  </taskdef>

  <!--==== Targets =========================================================-->

  <target name="installer"
    description="インストーラーを作成します。"
    depends="-dist.build.from-target,
             -installer.build">
    <mkdir dir="${installer.target.dir}"/>

    <izpack:compile
      input="${installer.build.dir}/install.xml"
      output="${installer.target.dir}/${dist.name}-installer.jar"
      basedir="${installer.build.dir}"
      inheritall="false">
      <propertyset>
        <propertyref name="dist.name"/>
        <propertyref name="dist.build.dir"/>
      </propertyset>
    </izpack:compile>
  </target>

  <target name="-dist.build.from-target">
    <mkdir dir="${dist.build.dir}"/>

    <unzip dest="${dist.build.dir}">
      <fileset dir="${dist.target.dir}">
        <include name="${dist.name}-bin.zip"/>
      </fileset>
      <cutdirsmapper dirs="1"/>
    </unzip>
  </target>

  <target name="-installer.build">
    <mkdir dir="${installer.build.dir}"/>

    <xslt
      destdir="${installer.build.dir}"
      style="./standalone.xsl"
      basedir="${installer.src.dir}">
      <identitymapper/>
    </xslt>
  </target>

</project>

DOCTYPE宣言除去用のXSLTスタイルシート (standalone.xsl)

DOCTYPE宣言除去用のXSLTスタイルシートは、テンプレートルールを一つだけ持つ。このテンプレートルールは、ソースツリーをそのままリザルトツリーとして出力するだけのシンプルなもの。この過程で (幸か不幸か) DOCTYPE宣言は除去される。

standalone.xsl
<?xml version="1.0" encoding="UTF-8"?>

<xsl:transform version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:template
    match="/">
    <xsl:copy-of
      select="child::node()"/>
  </xsl:template>

</xsl:transform>

ビルドスクリプトを実行する

ビルドスクリプトの実行は、先日の方法とまったく同じ。ビルドが完了すると、インストーラーがtarget/installerに生成される。このインストーラーをオフラインな環境で実行しても、件のエラーは発生しない。

ただ残念なことに、このビルドスクリプトはオンラインな環境でしか実行できない。職場 (=オフラインな環境) で使えるようにするためにも、この点を何とかしなければ……

2011年6月5日日曜日

Apache AntのインストーラーをApache Antでビルドする

先日作ったApache Antのインストーラーに問題があることがわかった。このインストーラーをオフラインな環境で実行すると、下記のエラーが発生してしまう。

Errornull at line 3, column 79 : javax.xml.transform.TransformerException: com.sun.org.apache.xml.internal.utils.WrappedRuntimeException: github.com

どうやら、インストール定義ファイルの外部DTD (registry.dtd) にアクセスできずに困っている模様。インストール定義ファイルはコンパイル時にすべて処理されるものだとばかり思っていたが、レジストリ関連のものはそうではないらしい……

対策を練る

このエラーは、インストール定義ファイルからDOCTYPE宣言を削除すれば発生しなくなる。が、アプリケーションの都合に合わせてデータを改変するのは極力避けたい。しばらく考えた結果、

  1. インストール定義ファイルには手を入れない (=DOCTYPE宣言を残しておく)
  2. コンパイル時に、1のファイルからDOCTYPE宣言を削除したものを生成し、それをコンパイルする

ことにした。

というわけで、まずは先日のインストーラー作成プロセスをビルドスクリプト化するところから。

ビルドスクリプトを作る

インストール定義ファイルのコンパイル処理だけをビルドスクリプトに、というのでもよかったのだが、せっかくなので、

  • 入手したバイナリディストリビューションを展開する
  • インストーラーの名前をバイナリディストリビューションの名前にそろえる

ということも併せてやってみる。

フォルダ構成

入手したApache Ant 1.8.2のバイナリディストリビューション (apache-ant-1.8.2-bin.zip) を、展開せずにtarget/distに格納しておく。このバイナリディストリビューションがbuild/distに展開され、それを取り込んだインストーラーがtarget/installerに生成される。

2011-06-05/
  +-- build.xml           // ビルドスクリプト
  +-- install.xml
  +-- registry-spec.xml
  +-- build/
  |     +-- dist/         // ここにバイナリディストリビューションが展開される
  |           +-- bin/
  |           +-- lib/
  |           +-- docs/
  |           +-- etc/
  +-- target/
        +-- dist/         // ここにバイナリディストリビューションを格納しておく
        |     +-- apache-ant-1.8.2-bin.zip
        +-- installer/    // ここにインストーラーが生成される
              +-- apache-ant-1.8.2-installer.jar

ビルドスクリプト (build.xml)

ビルドスクリプトは、下記のターゲットを持つ。

  • installer: インストーラーを作成する
  • -dist.build.from-target: (ZIPアーカイブを展開することで) バイナリディストリビューションの内容を生成する

インストーラーの作成には、IzPackに同梱のカスタムタスクを使う。また、下記のプロパティをインストール定義ファイルへ受け渡すようにした。

  • dist.name: バイナリディストリビューションの名前
  • dist.build.dir: バイナリディストリビューションの展開先
build.xml
<?xml version="1.0" encoding="UTF-8"?>

<project name="Apache Ant"
  default="installer"
  basedir="."
  xmlns:izpack="com.izforge.izpack">

  <!--==== Properties ======================================================-->

  <property environment="env"/>

  <property name="dist.name"
    value="apache-ant-1.8.2"/>

  <property name="build.dir"
    location="./build/"/>
  <property name="target.dir"
    location="./target/"/>

  <property name="dist.build.dir"
    location="${build.dir}/dist/"/>
  <property name="dist.target.dir"
    location="${target.dir}/dist/"/>

  <!--==== Task definitions ================================================-->

  <taskdef name="compile" uri="com.izforge.izpack"
    description="インストール定義ファイルをコンパイルします。"
    classname="com.izforge.izpack.ant.IzPackTask">
    <classpath>
      <pathelement location="${env.IZPACK_HOME}/lib/standalone-compiler.jar"/>
    </classpath>
  </taskdef>

  <!--==== Targets =========================================================-->

  <target name="installer"
    description="インストーラーを作成します。"
    depends="-dist.build.from-target">
    <local name="installer.target.dir"/>
    <property name="installer.target.dir"
      location="${target.dir}/installer/"/>

    <mkdir dir="${installer.target.dir}"/>

    <izpack:compile
      input="./install.xml"
      output="${installer.target.dir}/${dist.name}-installer.jar"
      basedir="."
      inheritall="false">
      <propertyset>
        <propertyref name="dist.name"/>
        <propertyref name="dist.build.dir"/>
      </propertyset>
    </izpack:compile>
  </target>

  <target name="-dist.build.from-target">
    <mkdir dir="${dist.build.dir}"/>

    <unzip dest="${dist.build.dir}">
      <fileset dir="${dist.target.dir}">
        <include name="${dist.name}-bin.zip"/>
      </fileset>
      <cutdirsmapper dirs="1"/>
    </unzip>
  </target>

</project>

インストール定義ファイル (install.xml)

インストール定義ファイルは、先日作ったものを一部手直しして使う。具体的には、ビルドスクリプトから受け取った下記のプロパティを参照するように書き換えた。

  • dist.name: バイナリディストリビューションの名前
  • dist.build.dir: バイナリディストリビューションの展開先
install.xml
  <info>
    <appname>Apache Ant™</appname>
    <appversion>1.8.2</appversion>
    <appsubpath>Apache Software Foundation/@{dist.name}</appsubpath>
  </info>
    <pack name="All files"
      required="yes">
      <description/>
      <fileset targetdir="${INSTALL_PATH}"
        dir="@{dist.build.dir}"/>
    </pack>

ビルドスクリプトを実行する

ビルドスクリプトの実行は、Mac OS X環境とWindows環境とのどちらででも行える。ビルドが完了すると、インストーラーがtarget/installerに生成される。

Mac OS X環境
$ pwd
/Users/(中略)/2011-06-05
$ export IZPACK_HOME=/Applications/IzPack
$ ant
Windows環境
C:\>cd
C:\Documents and Settings\(中略)\2011-06-05
C:\>SET IZPACK_HOME=%ProgramFiles%\IzPack
C:\>ant

準備が整ったので、次はインストール定義ファイルの加工に取り組もう。