概要
手元で docker + eclipse + eclim + vim な環境を構築しようとしている関係で、 gradle eclipse
が書き出す .classpath
ファイル内のファイルパスを絶対パスから相対パスに書き換えるようにしてみました。
準備
$ mkdir javajava/ && cd javajava/
docker コンテナから gradle を利用できる用のファイルを作成する。
Dockerfile:
FROM openjdk:8
WORKDIR /usr/local/app
ENV M2_HOME=/apache-maven-3.5.4/
ENV PATH=$PATH:/apache-maven-3.5.4/bin/:/gradle-4.8.1/bin/
RUN cd / && \
wget http://ftp.jaist.ac.jp/pub/apache/maven/maven-3/3.5.4/binaries/apache-maven-3.5.4-bin.tar.gz && \
tar xzvf apache-maven-3.5.4-bin.tar.gz && \
rm apache-maven-3.5.4-bin.tar.gz
RUN cd / && \
wget https://downloads.gradle.org/distributions/gradle-4.8.1-bin.zip && \
unzip gradle-4.8.1-bin.zip && \
rm gradle-4.8.1-bin.zip
docker-compose.yml:
version: "3"
services:
java8:
build: .
volumes:
- .:/usr/local/app
- .m2/:/root/.m2/
- .gradle/:/root/.gradle/
ホスト側の ./.gradle
をコンテナ側の /root/.gradle/
にマウントして、ホスト側にもキャッシュするようにしているので、別の eclimd コンテナからこのプロジェクトを参照する際に、 .classpath
内のパスが相対パスになっていてほしい、という感じ。
で、上記ファイルを作ると、とりあえず下記が実行できるようになる。
$ docker-compose run --rm java8 gradle tasks
だめなパターン
まずは、適当なビルドスクリプトを作成して、gradle eclipse
で .classpath
を書き出してみる。
build.gradle:
apply plugin: 'eclipse'
apply plugin: 'java-library'
repositories {
mavenCentral()
}
dependencies {
compile group: 'log4j', name: 'log4j', version: '1.2.17'
}
$ docker-compose run --rm java8 gradle eclipse
(略)
$ cat .classpath
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="output" path="bin/default"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8/"/>
<classpathentry sourcepath="/root/.gradle/caches/modules-2/files-2.1/log4j/log4j/1.2.17/677abe279b68c5e7490d6d50c6951376238d7d3e/log4j-1.2.17-sources.jar" kind="lib" path="/root/.gradle/caches/modules-2/files-2.1/log4j/log4j/1.2.17/5af35056b4d257e4b64b9e8069c0746e8b08629f/log4j-1.2.17.jar">
<attributes>
<attribute name="gradle_used_by_scope" value="main,test"/>
</attributes>
</classpathentry>
</classpath>
上記のようにパスが /root/.gradle
になってしまっていて、ほかでは使えない設定になってしまっている。
.classpath
を相対パスで書き出す
ここで build.gradle
に下記を追記する。
import java.util.regex.Pattern
import org.gradle.plugins.ide.eclipse.model.Library
import org.gradle.plugins.ide.eclipse.model.internal.FileReferenceFactory
eclipse {
classpath {
file {
whenMerged { classpath ->
classpath.getEntries().each {
if (it instanceof Library) {
def path = it.getPath()
def sourcePath = it.getSourcePath()
def pattern = Pattern.compile(gradle.gradleUserHomeDir.absolutePath)
it.setPath(path.replaceFirst(pattern, ".gradle"))
if(sourcePath) {
def newSourcePath = sourcePath.path.replaceFirst(pattern, ".gradle")
def fileReference = new FileReferenceFactory().fromPath(newSourcePath)
it.setSourcePath(fileReference)
}
}
}
}
}
}
}
gradle eclipse
を再実行してみる。
$ docker-compose run --rm java8 gradle eclipse (略)
$ cat .classpath
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="output" path="bin/default"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8/"/>
<classpathentry sourcepath=".gradle/caches/modules-2/files-2.1/log4j/log4j/1.2.17/677abe279b68c5e7490d6d50c6951376238d7d3e/log4j-1.2.17-sources.jar" kind="lib" path=".gradle/caches/modules-2/files-2.1/log4j/log4j/1.2.17/5af35056b4d257e4b64b9e8069c0746e8b08629f/log4j-1.2.17.jar">
<attributes>
<attribute name="gradle_used_by_scope" value="main,test"/>
</attributes>
</classpathentry>
</classpath>
root/.gradle
だったのが .gradle
になったので、java8 コンテナの外でも使える感じになった。
参考資料
-
Eclipse Classpath Editing — eclim (eclipse + vim)
-
.classpath
に書いてある内容の意味を把握するのに便利だった
-
-
EclipseClasspath - Gradle DSL Version 4.10
-
gradle eclipse
実行時に.classpath
の中身を書き換えるために必要な、whenMerged
フックが紹介されている
-
-
gradle/FileReferenceFactory.java at master · gradle/gradle
- gradle 的に classpathentry の sourcePath 属性のほうだけよく分からないけど FileReference というインタフェースで表現してた
-
FileReference (Gradle API 4.10)
- 上記のインタフェース
-
How do I create a concrete instance of FileReference? - Old Forum - Gradle Forums
- 動的に FileReference を実装したクラスのオブジェクトを生成する方法