Skip to content

Commit

Permalink
Add the generated source folders to Eclipse classpath entries
Browse files Browse the repository at this point in the history
- add the generated source folders to Eclipse classpath entries. Due to
  a limition of Buildship, we have to create those folders beforehand,
  see: eclipse-buildship/buildship#1196

Signed-off-by: sheche <[email protected]>
  • Loading branch information
jdneo authored and rougsig committed Aug 29, 2022
1 parent b6808f3 commit 6f3a73d
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,8 @@ class ProtobufPlugin implements Plugin<Project> {
project.tasks.withType(GenerateProtoTask).each { GenerateProtoTask generateProtoTask ->
generateProtoTask.getOutputSourceDirectories().each { File outputDir ->
Utils.addToIdeSources(project, generateProtoTask.isTest, outputDir, true)
Utils.addToEclipseSources(project, generateProtoTask.isTest,
generateProtoTask.sourceSet.name, outputDir)
}
}
}
Expand Down
72 changes: 72 additions & 0 deletions src/main/groovy/com/google/protobuf/gradle/Utils.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ import groovy.transform.CompileStatic
import org.apache.commons.lang.StringUtils
import org.gradle.api.Project
import org.gradle.api.tasks.SourceSet
import org.gradle.plugins.ide.eclipse.model.Classpath
import org.gradle.plugins.ide.eclipse.model.ClasspathEntry
import org.gradle.plugins.ide.eclipse.model.EclipseModel
import org.gradle.plugins.ide.eclipse.model.SourceFolder
import org.gradle.plugins.ide.idea.GenerateIdeaModule
import org.gradle.plugins.ide.idea.model.IdeaModel
import org.gradle.util.GUtil
Expand Down Expand Up @@ -129,4 +133,72 @@ class Utils {
}
}
}

/**
* Add the the folder of generated source to Eclipse .classpath file.
*/
static void addToEclipseSources(Project project, boolean isTest, String sourceSetName, File f) {
project.plugins.withId("eclipse") {
File projectDir = project.getProjectDir()

EclipseModel model = project.getExtensions().findByType(EclipseModel)
model.classpath.file.whenMerged { Classpath cp ->
// buildship requires the folder exists on disk, otherwise
// it will be ignored when updating classpath file, see:
// https://github.com/eclipse/buildship/issues/1196
f.mkdirs()

String relativePath = projectDir.toURI().relativize(f.toURI()).getPath()
// remove trailing slash
if (relativePath.endsWith("/")) {
relativePath = relativePath.substring(0, relativePath.length() - 1);
}
SourceFolder entry = new SourceFolder(relativePath, getOutputPath(cp, sourceSetName))
entry.entryAttributes.put("optional", "true")
entry.entryAttributes.put("ignore_optional_problems", "true")
// check if output is not null here because test source folder
// must have a separate output folder in Eclipse
if (entry.output != null && isTest) {
entry.entryAttributes.put("test", "true")
}
cp.entries.add(entry)
}
}
}

/**
* Get the output path according to the source set name, if no valid path can be
* found, <code>null</code> will return.
*/
private static String getOutputPath(Classpath classpath, String sourceSetName) {
String path = "bin/" + sourceSetName
if (isValidOutput(classpath, path)) {
return path
}
// fallback to default output
return null
}

/**
* Check if the output path is valid or not.
* See: org.eclipse.jdt.internal.core.ClasspathEntry#validateClasspath()
*/
private static boolean isValidOutput(Classpath classpath, String path) {
Set<String> outputs = new HashSet<>()
for (ClasspathEntry cpe : classpath.getEntries()) {
if (cpe instanceof SourceFolder) {
outputs.add(((SourceFolder) cpe).getOutput())
}
}
for (String output : outputs) {
if (Objects.equals(output, path)) {
continue
}
// Eclipse does not allow nested output path
if (output.startsWith(path) || path.startsWith(output)) {
return false
}
}
return true
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,46 @@ class ProtobufJavaPluginTest extends Specification {
gradleVersion << GRADLE_VERSIONS
}
@Unroll
void "testProject proto and generated output directories should be added to Eclipse [gradle #gradleVersion]"() {
given: "project from testProject"
File projectDir = ProtobufPluginTestHelper.projectBuilder('testEclipse')
.copyDirs('testProjectBase', 'testProject')
.build()
when: "eclipse is invoked"
BuildResult result = GradleRunner.create()
.withProjectDir(projectDir)
.withArguments('eclipse')
.withPluginClasspath()
.withGradleVersion(gradleVersion)
.build()
then: "it succeed"
result.task(":eclipse").outcome == TaskOutcome.SUCCESS
Node classpathFile = new XmlParser().parse(projectDir.toPath().resolve(".classpath").toFile())
Collection srcEntries = classpathFile.classpathentry.findAll {it.'@kind' == 'src'}
assert srcEntries.size() == 6
Set<String> sourceDir = [] as Set
srcEntries.each {
sourceDir.add(it.@path)
}
Set<String> expectedSourceDir = ImmutableSet.builder()
.add('src/main/java')
.add('src/test/java')
.add('build/generated/source/proto/grpc/java')
.add('build/generated/source/proto/grpc/grpc_output')
.add('build/generated/source/proto/main/java')
.add('build/generated/source/proto/test/java')
.build()
assert Objects.equals(expectedSourceDir, sourceDir)
where:
gradleVersion << GRADLE_VERSIONS
}
@Unroll
void "test proto generation is not up-to-date on dependency changes [gradle #gradleVersion]"() {
given: "project from testProject"
Expand Down
1 change: 1 addition & 0 deletions testProject/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
plugins {
id 'java'
id 'idea'
id 'eclipse'
id 'com.google.protobuf'
}
apply from: 'build_base.gradle'

0 comments on commit 6f3a73d

Please sign in to comment.