leftovers...

about grails groovy

Grails-1.0.*からGrails-1.1への〜 Pt.4 プラグインがより便利にあつかえる!

Grails-1.1からのプラグインの新機能のお話し。
Grails-1.1に追加された機能はこんな感じです。

わかりやすいようでわかりにくい。

はじめにグローバルプラグイン
これは、だいぶ前にxmlDo.net - Grails Web Development: そろそろ grails-1.1-SNAPSHOTをさわってみる。 Pt.1 Plugins編にも書いたのですが、おさらい。

grails install-plugin testing -global

"-global"オプションを指定することによって、プラグインはグローバルプラグインとして管理されます。
つまり、インストールされたプラグインは、同じ場所に保管されて、一度インストールすれば、同じバージョンのGrailsで他のアプリケーション開発するときは再度インストールすることなく使用することができます。
インストールしたプラグインは、対象のZipファイルが、USER_HOME/.grails/1.1-RC1/plugins/に保存されて、USER_HOME/.grails/1.1-RC1/global-plugins/ にプラグインのZipファイルが展開されます。
ただ、グローバルにインストールすると、プラグインを使用停止することができません。必ずロードされます、メタ情報になっている、application.properties内を書きかえても毎回メタ情報が追記されます。
グローバルプラグインとしてインストールする際は、必ず使う!という覚悟でインストールしましょう。
プラグインをグローバルから削除したい場合は、uninstall-pluginコマンドで削除できます。

grails uninstall-plugin testing

グローバルプラグインだと、意外と開発中に小回りがきかないような!?
そんなあなたにこんな機能!

この辺を一気に検証したので、まとめておきます。

前にも書いたかもしれませんが、Grails-1.1からプラグインは基本的にapplication.propertiesにメタ情報で管理されます。
application.properties

app.version=0.1
plugins.acegi=0.5.1
app.servlet.version=2.4
app.grails.version=1.1-SNAPSHOT
plugins.hibernate=1.1-beta3
app.name=relationsample

plugins.プラグイン名=バージョン

他には、単純にダウンロードしたプラグインを適当な場所に展開して、展開先のパスをBuildConfig.groovyに指定する方法があります。
BuildConfig.groovy

grails.plugin.location."ext"="./plugins/ext-0.1"
grails.plugin.location."navigation"="./plugins/navigation-1.0"
grails.plugin.location."rhino"="./plugins/rhino-0.1.1"
grails.plugin.location."yui"="./plugins/yui-2.6.0"

grails.plugin.location."プラグイン名"="./プラグインへの/パス"

この方法ですと、application.propertiesにプラグイン関連のメタ情報を記入する必要がありません。
この方法は1.0.x系からのアップグレードに便利です。*1

このBuildConfig.groovyに記述する方法を使うと、プラグインを"grails install-plugin something"のようにコマンドを使用してインストールする必要がありません。
これが「プラグインでのモジュール式アプリケーション開発」という内容に関連してきます。
公式のリリースノートに書かれているのとほぼ同じですが、「プラグインでのモジュール式アプリケーション開発」は、こんな時に有用です。

  • 複数のアプリケーション開発で同じセットのプラグインを使用するケース。

ディレクトリにプラグインを解凍して、複数のプロジェクトから参照。1.0.x系の時はプロジェクト毎にプラグインの管理をしていた為、同じプラグイン関連ファイルを複数保持することになり、プラグインの中身をそれぞれ改造しまえば、他のプロジェクトにも反映したい場合には、同じ場所をさがして書きかえ・・・と、結構面倒だったのですが、プラグインを統一管理して、同じ内容のBuildConfig.groovyをそれぞれに設定しておけば管理もスマート!

  • プラグイン開発者が実際にアプリケーションで動作確認する際。

プラグインGrailsアプリケーションと全く同じ構造なので、プラグインを開発するときは、そのまま起動(run-app)して動作を確認すれば良いと、Grails徹底入門にも書きました。しかし、動作確認用のソースファイル、他のプラグインと連携するプラグインを開発する際にインストールしたプラグインが、開発中のプラグインのプロジェクト内を汚してしまい、管理しにくくなってしまいます。
プラグイン開発時に、検証用のプロジェクトを作成して、開発中のプラグインプロジェクトを参照して動作確認すれば、これを解消できます。



ここまで一度まとめると、

  • 絶対に内容を変更しないし、絶対にどの開発でも使うよ!!というプラグインは、-globalのオプションでインストールすれば、嫌でもそのプラグインを使うことができます。
  • 絶対では無いのだけど、開発の内容によっては、確実に使うプラグイン(プラグインのセット)があるよ!!という場合は、BuildConfig.groovyファイルに、grails.plugin.location."プラグイン名"="./プラグインへの/パス"を記述して、プラグインを使えます。


チーム開発でかなり役に立ちます。
でも!-globalは強引過ぎだし、grails.plugin.location指定だと、チームメンバー依存するよね!?それぞれが、プラグインを改変したら、大変だよ!
では、grails.plugin.location."プラグイン名"="./プラグインへの/パス"の"./プラグインへの/パス"をリポジトリ管理してしまえば良いんじゃない!?
それでも良いと思いますが、少し違います

そこで、今回の新機能に注目!

Grails-1.1から独自のプラグインリポジトリを設定することができるようになりました。

設定方法
USER_HOME/.grails/settings.groovy 又は、grails-app/conf/BuildConfig.groovyに設定。例えば、チームのプラグインリポジトリに使用するSvnのUrlが、"http://127.0.0.1/gp"だとしたら、

grails.plugin.repos.discovery.local="http://127.0.0.1/gp" 
grails.plugin.repos.distribution.local="http://127.0.0.1/gp"

ぁ、どっちがどの意味か調べてない・・・まあ文字通りですが・・

grails.plugin.repos.discovery.リポジトリ名称="リポジトリへのHttpベースのURL"
grails.plugin.repos.distribution.リポジトリ名称="リポジトリへのHttpベースのURL"

この設定をすることによって、プラグイン関連のコマンドlist-plugins,install-pluginで設定したプラグインリポジトリも同時に参照してくれます。個別に参照する場合は、以下のように設定したリポジトリ名称を指定します。

grails list-plugins -repository=リポジトリ名称

指定したリポジトリプラグインが無い場合は、何も無いよ的なメッセージがでます。*3

独自のプラグインリポジトリプラグインをリリース
プラグインプロジェクトディレクトでrelease-pluginに-repository=対象リポジトリ名称を指定して実行。

grails release-plugin -repository=local

このコマンドでは、プラグインの管理のルールに従った作業内容を自動で行ってくれます。プラグインのプロジェクトをあらかじめsvnに追加しておく必要がありません。(追記:リポジトリ上の階層は最初のプラグインリリースで自動生成されます。2度目のリリースからは、リポジトリに生成された階層を、ローカルにチェックアウトした、trunkからリリースを実行します)

  1. プラグインのパッケージング
  2. プラグインリポジトリへのプラグインの追加(grails-プラグイン名の階層のしたに、tags trunkを追加)
  3. プラグインのバージョンを自動でタグ切り
  4. プラグインリポジトリにある、プラグイン管理用の.plugin-meta/plugins-list.xmlを更新

コマンドを実行すると、SVNのユーザ名、パスワードを聞いてきますので、コミットのユーザ権限を設定しておけば管理もちゃんとできます。

で、何故独自のプラグインリポジトリを作ると良いのか!?というと、
他動的なプラグイン自動解決 (Automatic Transitive Plugin Resolution)の話になります。
先にも述べたように、Grails-1.1でのこの実装で、プラグインはapplication.propertiesに記述されたメタ情報で管理されるようになり、メタ情報に記述されていれば、"grails run-app"等の際に、プラグインがインストールされていなければ自動的にインストールされ、プラグインのバージョンがインストールされているプラグインのバージョンと違えば、古いプラグインをアンインストールして新たにインストールしてくれます。
つまり、今までは、公式ではないプラグインを使ったプロジェクトをチーム開発する際は、全員がそれぞれプラグインをインストールしてから、アプリケーションを起動していました。その際にバージョンを間違えたり等で、余計なトラブルが起きるケースもあったのですが、Grails-1.1からは、プラグインをapplication.propertiesに書いてあれば、インストールも自動で行ってくれるので、入れ忘れも無く、独自のプラグインリポジトリも扱えるので公式でないプラグインを管理するのも楽々です。

開発プロジェクトでのプラグイン管理と設定は、こんな感じになるでしょう。

  • grails-app/conf/BuildConfig.groovyに、開発プロジェクトで使うプラグインリポジトリの設定をする。
  • application.propertiesには、各プラグインのメタ情報を記述。
  • 上記の情報をアプリケーションプロジェクトに追加してプロジェクトのSVN等に置いておく。
  • チームのメンバーは、それぞれチェックアウト、アップデートで、プラグインの情報は自動で認識されるので、プラグインの依存を気にすることなく開発。

他には、

  • メインのプロジェクトは、プラグイン関連の定義のみが置いてある。
  • それぞれの機能をプラグインとしてチームのそれぞれが開発。
  • プラグインを更新したらメインのプロジェクトの対象になるプラグインバージョンを変更
  • メインのプロジェクトをHudsonとか利用して自動で結合テストを行う。

ビジネスとして使うには!?

まとめ

おまけ
あまり検証していないので、おまけ扱いです。
プラグインの スコープと環境
プラグイン開発で、プラグインを使用できる環境(dev test等)を指定できるようになりました。
テスト環境のみで使用できるプラグインとかできます。

def environments = ['dev', 'test']

スコープは、以下の用に指定することによって、以下の例では、warに書き出す際にはパッケージにプラグインは含まない指定ができます。

def scopes = [excludes:'war']

これらの設定をすることによって、開発時のみに必要な開発用のプラグインは、デプロイ時に除外できるようになりました。


なんか、長すぎでよけいにわかりにくくなってしまったかも・・・。
G*系ユーザ会でサックリ説明できるように、スライドにまとめるかな・・・・

*1:Grails-1.0.*からGrails-1.1への〜 Pt.1 - leftovers...も参照

*2:ホントの訳・・・は???

*3:エラーも出たかも