Output relative path in .classpath file generated by gradle eclipse

Overview

Since I am trying to build an environment of docker + eclipse + eclim + vim at hand, I tried to rewrite the file path in the .classpath file written by gradle eclipse from an absolute path to a relative path.

Preparation

$ mkdir javajava/ && cd javajava/

Create a file for using gradle from docker container.

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/

I mount ./.gradle on the host side to /root/.gradle/ on the container side and cache it on the host side as well, so when I refer to this project from another eclimd container , I want the path in .classpath to be a relative path.

So, if you create the above file, you can execute the following for the time being.

$ docker-compose run --rm java8 gradle tasks 

Bad pattern

First, create a suitable build script and write .classpath with gradle eclipse.

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
(Abbreviation)
$ 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>

As mentioned above, the path is /root/.gradle, and it is a setting that can not be used anywhere else.

Export .classpath as a relative path

Here, add the following to 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)
                        }
                    }
                }
            }
        }
    }
}

Try re-running gradle eclipse.

$ docker-compose run --rm java8 gradle eclipse                                                                        (Abbreviation)
$ 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>

It was root / .gradle, but now it's .gradle, so it feels like it can be used outside the java8 container.

Reference material

Recommended Posts

Output relative path in .classpath file generated by gradle eclipse
How to debug the generated jar file in Eclipse
Put the date (e.g. yyyy-MM-dd) in the log file output by logback
Log output to file in Java
Enable log output to both file and console using log4j in Eclipse.
Relative path when running tomcat on eclipse
FindBugs in Gradle doesn't output results in HTML
File output bean as JSON in spring