GradleのEclipseプラグインの処理結果を変更
GradleのEclipseプラグインは、build.gradleに記述した通りに、Eclipseの.projectファイル.classpathファイルを書き換えてくれるので非常に便利なのだが、しかし意図しない状態になってしまうことがある。これを修正する。
GradleのEclipseプラグインの問題
ソースフォルダを複数回記述してしまう
ビルドの都合で、以下のように同じソースフォルダを複数記述している。
sourceSets {
main {
java {
srcDir 'src_common'; exclude '**/*Test.java';
...
}
}
foobar {
java {
srcDir 'src_common'; exclude '**/*Test.java';
}
}
}
すると、このプラグインは、Eclipseのビルドパスに同じsrc_commonというソースフォルダを複数回記述してしまう。これはEclipse側としては気に入らないため、当然エラー状態になり、手で修正せざるをえない。
excludeを入れ込んでしまう
前述の例のようにソースフォルダに「exclude ‘**/*Test.java’」という記述をしておくと、これまたご丁寧なことに、Eclipseのビルドパスにもこの記述を再現してしまう。これらの*Test.javaというクラスは、ビルド時には見えなくなってほしいのだが、開発環境では見えていて欲しいのであるにも関わらず。
Allow output folders for source foldersがONになっている
ビルドパスの中のこの指定は複数のソースフォルダがある場合に、そのコンパイル結果を一つにせず、別々のフォルダに出力するという意味なのだが、これが勝手にONになる。OFFにさせる方法は無いようだ。
すべてのbuild.gradleに共通のリンクファイルを.projectに記述したい。
これについては後の方で説明する。
eclipseプラグイン動作の変更
他にやり方はあるかと思うが、Gradleが良くわからない私にとって最も簡単な方法をとった。とりあえずこれで行くことにする。
まず、build.gradleにeclipseプラグインに関する動作変更を記述する。.classpath、.projectの両者についてwhenMergedの時点で修正するクロージャを指定する。
eclipse {
// .classpathについての変更
classpath {
// ソースもダウンロード
downloadSources=true
// 出力フォルダの指定
defaultOutputDir = file('bin')
// whenMergedで修正する
file whenMergedEclipseClassPathMod
}
// .projectについての変更
project {
// whenMergedで修正する
file whenMergedEclipseProjectMod
}
}
.classpathの変更
.classpathに関する変更クロージャwhenMergedEclipseClassPathModは以下のようなものである。
なお、この処理は共通化するために関数にはしていない。クロージャとして実現している。
/** eclipseプラグインのprojectについてwhenMergedの時点で修正を行う */
whenMergedEclipseClassPathMod = {
whenMerged {cp->
removeDuplicatedSources(cp)
removeOutputFoldersForSourceFolders(cp)
removeAllExcludes(cp)
}
}
/* sourceSetsで同じフォルダを複数回指定すると、ご丁寧にもその分だけ
* classPathに入れてしまう。重複した分を削除する
*/
removeDuplicatedSources = { cp->
def newList = new ArrayList()
def duplicated = new HashSet()
cp.entries.each { e->
if (e.kind != 'src') {
newList.add(e);
return
}
if (duplicated.contains(e.path))
return;
newList.add(e);
duplicated.add(e.path);
}
cp.entries = newList;
}
// srcDir 'src'; exclude '**/*Test.java';のexcludeを削除する。
// IDE上ではテストユニットが見えていて欲しい
removeAllExcludes = { cp->
cp.entries.findAll{ it.kind == 'src' }.each{
it.setExcludes(new ArrayList())
}
}
/* 勝手に指定されたoutputを削除する。
* これがあると、勝手にAllow output folders for source foldersがONになってしまう。
*/
removeOutputFoldersForSourceFolders = { cp->
cp.entries.findAll{ it.kind == 'src' }.each{
it.output = null
}
}
.projectの変更
.projectに関する変更のためのクロージャは以下のようなものである。Eclipseの各プロジェクトに、共通ファイルへのリンクをつけるものだが、これについては後で説明する。
eclipseProjectMod = { proj->
addCommonGradle(proj)
}
addCommonGradle = { proj ->
proj.linkedResources.add(new org.gradle.plugins.ide.eclipse.model.Link(
'common.gradle', '1', 'C:/Foo/Bar/common.gradle', null));
}
これは、単純にlinkedResourcesにエントリを追加するだけなので、以下のように記述してもよい。
eclipse {
project {
linkedResource name: 'common.gradle', type: '1', location: 'C:/Foo/Bar/common.gradle'
}
}
eclipseプラグインへの修正クロージャを共通ファイルにまとめ、Eclipseプロジェクトから閲覧する
これらのeclipseプラグインについての動作修正処理を、各プロジェクトのbuild.gradleに毎回記述するのも面倒なので、共通ファイル化する。これについては、build.gradleの共通設定に記述した。
つまり、common.gradleは、各プロジェクトから独立した存在であり、ユーザホーム以外の場所に設置することができる。
しかし、各Eclipseプロジェクトからこれが見えて欲しいのである。各々のEclipseプロジェクトに取り組んでいるあいだに、新たなものをcommon.gradleに入れたくなるかもしれない。
Eclipse IDEから行う方法とその結果
これをEclipseIDEで行うには次のようにする。
まずプロジェクトを右クリックし、Fileを選択する。
Advancedをクリックし、Link to file in the file systemをチェックする。
後はBrowseで、ファイルを指定すればよい。すると、Eclipseプロジェクト中にcommon.gradleが「リンクされた状態」で現れる。つまり、ファイルのコピーではなく、いわばプロジェクト外のファイルを直接見れるようになる。
.project再作成の際に消える問題
しかし、GradleのEclipseプラグインが機能すると、こんな事情は知るよしも無いので、手作業で作成したリンクを消しさってしまう。
そのために、先のeclipseProjectModクロージャを作成した。.projectファイルの再作成に際し、常にこのリンクを保持する。
再度だが、単に以下のように書いてもよい。
eclipse {
project {
linkedResource name: 'common.gradle', type: '1', location: 'C:/Foo/Bar/common.gradle'
}
}