2011年8月12日金曜日

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

特に急ぐこともなく暇を見つけて取り組んできたApache Antのインストーラー作りだが、諸事情により少しペースを上げることにした。Mac OS X環境へのインストール周りをもっと詰めたかったのだが、ひとまず諦めて先に下記の4項目を片付けておく。

  1. インストールするコンポーネントを選べるようにする
  2. インストール先を指定できるようにする
  3. インストーラーのルックアンドフィールをカスタマイズする
  4. EULAを確認できるようにする

インストールするコンポーネントを選べるようにする

バイナリディストリビューションには5個のフォルダといくつかのファイルとが含まれている。このうち、Apache Antの実行に必要なのはbinフォルダとlibフォルダだけ[1]。そこで、必要なものだけを選んでインストールできるよう、PacksPanelを追加する。

パックの名前および説明は、Installing Antのディレクトリレイアウト図に倣った。なお、パック名を変える際は、それを参照しているレジストリ定義ファイル (registry-spec.xml) の書き換えも忘れずに。

詳細は下記を参照。

インストール先を指定できるようにする

有無を言わさず/ApplicationsフォルダやC:\Program Filesフォルダなどにインストールしてしまうのは、シンプルでわかりやすい反面、困ったことにも (例: Cドライブに余裕がない、パスに空白文字が含まれるのは……、など)。ここでは、シンプルさよりも運用時の柔軟性を優先し、DefaultTargetPanelをTargetPanelに替えることにする。

詳細は下記を参照。

インストーラーのルックアンドフィールをカスタマイズする

Apache Antにはロゴがある。せっかくロゴがあるのだから、これを使ってインストーラーのルックアンドフィールをカスタマイズする。併せてインストーラーのタイトルもそれらしくいじってみる。

詳細は私的リポジトリ (r21) を参照。

EULAを確認できるようにする

世のインストーラーに倣って、インストール時にEULAを表示/確認できるようにする。なお、追加するパネルはLicensePanelではなくLicencePanel[2]

一つだけ残念なのは、EULAの一部の文字が化けてしまうこと (W3C®W3Cツョ)。IzPackのBTSではこの不具合はIzPack 4.3.4で修正されたとなっている[3]が、手元の環境 (IzPack 4.3.4) では不具合が再現してしまう。

というわけで、日本語環境 (非ISO-8859-1環境?) では下記のどちらかの対策が必要な模様。

  1. インストール定義時: LICENSEファイルのエンコード形式を明示する

    <res id="LicencePanel.licence"
      src="LICENSE"
      encoding="ISO-8859-1"/>

    インストーラー実行時: システムプロパティfile.encodingに値UTF-8を指定して実行する

    java -Dfile.encoding=UTF-8 -jar installer.jar
  2. インストール定義時: LICENSEファイルのエンコード形式を明示しない

    <res id="LicencePanel.licence"
      src="LICENSE"/>

    インストーラー実行時: システムプロパティfile.encodingに値ISO-8859-1を指定して実行する

    java -Dfile.encoding=ISO-8859-1 -jar installer.jar

詳細は私的リポジトリ (r23) を参照。

2011年7月10日日曜日

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

先日の積み残しに対して、「これだったらXMLカタログを使えば楽勝だろう」と高をくくっていたところ、とんでもないワナが潜んでいた。頭の中で考えるのと実際に手を動かすのとではやっぱり違う、ということを改めて思い知らされた。

Apache Ant (Mac OS X同梱版) のワナ

Apache Antで外部XMLカタログファイルを使う場合、Apache XML Commons Resolverが必要になる[1]。具体的には、Apache Antの実行時クラスパスにApache XML Commons Resolverを含めてやる[2]必要があるのだが、Mac OS X同梱のApache Antではどういうわけかそれができなかった。

-libオプションで指定してみた
$ pwd
/Users/ (中略) /playpit/trunk/apache-ant
$ ant -lib /path/to/resolver.jar
CLASSPATH環境変数で指定してみた
$ pwd
/Users/ (中略) /playpit/trunk/apache-ant
$ export CLASSPATH=/path/to/resolver.jar
$ ant
${user.home}/.ant/libフォルダに格納してみた
$ pwd
/Users/ (中略) /playpit/trunk/apache-ant
$ ls ~/.ant/lib/
resolver.jar
$ ant

上記のいずれの方法でも、

Warning: XML resolver not found; external catalogs will be ignored

という警告が出て、オフラインでのXSLT変換に失敗してしまう。もちろん、バイナリディストリビューション版であれば問題なくビルドできる。

しばらくWebをさまよってみたもののそれらしい情報にはたどり着けず、やむなくMac OS X同梱版のApache Antを使うのは諦めることにした。

フォルダ構成

気を取り直して、XMLカタログおよびDTDファイルをビルドスクリプトに組み込む。XMLカタログは自作するとして、DTDファイルはIzPackに同梱されているものを使おう、と思ったのだが、どうやら最新版のIzPack (4.3.4) にはDTDファイルが同梱されていない模様。GitHubから入手してもよかったのだが、DTDバリデーションを行うわけではないのでダミーのDTDファイルで済ませることにする。

apache-ant/
  +-- build.xml
  +-- standalone.xsl
  +-- src/
  |     +-- installer/
  +-- lib/
  |     +-- izpack-4.3/
  |           +-- catalog.xml                 // XMLカタログファイル
  |           +-- dtd/
  |                 +-- installation.dtd      // ダミーのDTDファイル
  |                 +-- event/
  |                       +-- registry.dtd    // ダミーのDTDファイル
  +-- build/
  |     +-- dist/
  |     +-- installer/
  +-- target/
        +-- dist/
        +-- installer/

詳細は私的リポジトリを参照。

メモ: XMLカタログのバージョン

  • XMLカタログにはバージョン1.0と1.1とがある (できればバージョン1.1を使いたい)。
  • Apache XML Commons Resolver 1.2は、バージョン1.0と1.1 (の一部?) との両方のXMLカタログをサポートしている。
  • ただし、Apache XML Commons Resolver 1.2はバージョン1.1のXMLカタログをブートストラップできない。
  • バージョン1.1のXMLカタログを使いたい場合は、5.2. “Bootstrapping” Catalog Resolutionの解説に従ってDOCTYPE宣言のシステム識別子を書き換えるか、DOCTYPE宣言そのものを削除する必要がある。

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

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

2011年5月29日日曜日

Apache Antのインストール

いくつかあるやりたいことのうち、まずはApache Antに取り組んでみる。自宅と職場との両方で使いたいので、Mac OS X環境とWindows環境との両方を視野に入れて進めることにした。

手元の環境の確認

手元のMac OS X環境 (10.6.7) は、

$ ant -version
Apache Ant(TM) version 1.8.2 compiled on February 28 2011

ということで、すでにApache Antがインストールされており、すぐに使える模様。

手元のWindows環境 (2000 SP4) は、

C:\>ant -version
'ant' は、内部コマンドまたは外部コマンド、
操作可能なプログラムまたはバッチ ファイルとして認識されていません。

ということで、まずはApache Antをインストールするところから。

インストーラーを作る

Installing Antの手順に従って手作業でインストールを、というのでもよかったのだが、せっかくなのでApache Antのインストーラーを作ってみる。インストーラーの作成にはIzPackを使うことにした。

フォルダ構成

Apache Ant 1.8.2のバイナリディストリビューション (apache-ant-1.8.2-bin.zip) を入手・展開し、それに合わせてIzPack用のインストール定義ファイル (install.xmlregistry-spec.xml) を記述する。このインストール定義ファイルをIzPackでコンパイルすると、インストーラー (installer.jar) が生成される。

2011-05-29/
  +-- install.xml          // インストール定義ファイル
  +-- registry-spec.xml    // インストール定義ファイル (レジストリ関連)
  +-- apache-ant-1.8.2/    // 入手したバイナリディストリビューションを展開したもの
  |     +-- bin/
  |     +-- lib/
  |     +-- docs/
  |     +-- etc/
  +-- installer.jar        // 生成されたインストーラー

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

インストール定義は、バイナリディストリビューション中の全ファイルを%ProgramFiles%\Apache Software Foundation\apache-ant-1.8.2にインストールする、という単純なもの。加えて、環境変数ANT_HOMEの追加と環境変数Pathの変更とを行うようにした。

install.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE installation
  SYSTEM "https://github.com/jponge/izpack/raw/4.3/src/dtd/installation.dtd">

<installation version="1.0">

  <info>
    <appname>Apache Ant™</appname>
    <appversion>1.8.2</appversion>
    <appsubpath>Apache Software Foundation/apache-ant-${APP_VER}</appsubpath>
  </info>

  <guiprefs width="640" height="480" resizable="no"/>

  <locale>
    <langpack iso3="jpn"/>
  </locale>

  <resources>
    <res id="RegistrySpec.xml"
      src="./registry-spec.xml"/>
  </resources>

  <panels>
    <panel classname="HelloPanel"/>
    <panel classname="DefaultTargetPanel"/>
    <panel classname="SummaryPanel"/>
    <panel classname="InstallPanel"/>
    <panel classname="SimpleFinishPanel"/>
  </panels>

  <listeners>
    <listener
      installer="RegistryInstallerListener"
      uninstaller="RegistryUninstallerListener">
      <os family="windows"/>
    </listener>
  </listeners>

  <packs>
    <pack name="All files"
      required="yes">
      <description/>
      <fileset targetdir="${INSTALL_PATH}"
        dir="./apache-ant-1.8.2/"/>
    </pack>
  </packs>

  <native type="3rdparty" name="COIOSHelper.dll" stage="both">
    <os family="windows"/>
  </native>

</installation>
registry-spec.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE registry
  SYSTEM "https://github.com/jponge/izpack/raw/4.3/src/dtd/event/registry.dtd">

<registry>

  <pack name="All files">
    <value
      name="ANT_HOME"
      string="${INSTALL_PATH}"
      keypath="SYSTEM\CurrentControlSet\Control\Session Manager\Environment"
      root="HKLM"/>
    <value
      name="Path"
      string="${OLD_KEY_VALUE};%ANT_HOME%\bin"
      keypath="SYSTEM\CurrentControlSet\Control\Session Manager\Environment"
      root="HKLM"/>
  </pack>

</registry>

コンパイル

これらのインストール定義ファイルを、IzPackのcompileコマンドを用いてコンパイルする。コンパイルは、Mac OS X環境とWindows環境とのどちらで行ってもよい。

Mac OS X環境
$ pwd
/Users/(中略)/2011-05-29
$ export PATH=${PATH}:/Applications/IzPack/bin
$ compile install.xml -o installer.jar
Windows環境
C:\>cd
C:\Documents and Settings\(中略)\2011-05-29
C:\>SET Path=%Path%;%ProgramFiles%\IzPack\bin
C:\>compile install.xml -o installer.jar

インストーラーを実行する

生成されたインストーラーを実行したのちに、追加・変更された環境変数を認識させるためにWindowsを再起動する。これでApache Antがインストールされたはず。正しくインストールされたかどうかを確認してみる。

C:\>ant -version
Unable to locate tools.jar. Expected to find it in C:\Program Files\Java\jre6\li
b\tools.jar
Apache Ant(TM) version 1.8.2 compiled on December 20 2010

正しくインストールされた模様。

2011年5月27日金曜日

ふと思い立つ

ふと思い立ったので、ちょうどいい機会なので、とりあえず始めてみよう。