Skip to content

Commit

Permalink
[eclipse/xtext-core#1835] better treatment of unsupported Java versio…
Browse files Browse the repository at this point in the history
…ns in Xtext

Signed-off-by: Christian Dietrich <[email protected]>
  • Loading branch information
cdietrich committed Feb 19, 2022
1 parent 1738f18 commit 5df47a7
Showing 1 changed file with 59 additions and 68 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import java.net.URLClassLoader
import java.util.List
import java.util.Set
import java.util.concurrent.ConcurrentHashMap
import org.eclipse.emf.common.notify.Notifier
import org.eclipse.emf.common.util.URI
import org.eclipse.xtext.ISetup
import org.eclipse.xtext.build.BuildRequest
Expand Down Expand Up @@ -52,7 +51,7 @@ class XtextGradleBuilder implements IncrementalXtextBuilder {
val sharedInjector = Guice.createInjector
val incrementalbuilder = sharedInjector.getInstance(IncrementalBuilder)
val debugInfoInstaller = sharedInjector.getInstance(DebugInfoInstaller)

new(Set<String> setupNames, String encoding) throws Exception {
System.setProperty("org.eclipse.emf.common.util.ReferenceClearingQueue", "false")
for (setupName : setupNames) {
Expand All @@ -67,12 +66,12 @@ class XtextGradleBuilder implements IncrementalXtextBuilder {
val containerHandle = gradleRequest.containerHandle
val validator = new GradleValidatonCallback(gradleRequest.logger)
val response = new GradleBuildResponse

indexChangedClasspathEntries(gradleRequest)

val request = new BuildRequest => [
baseDir = createFolderURI(gradleRequest.projectDir)
if(needsCleanBuild(gradleRequest)) {
if (needsCleanBuild(gradleRequest)) {
dirtyFiles = gradleRequest.allFiles.map[URI.createFileURI(absolutePath)].toList
state = new IndexState
} else {
Expand All @@ -84,28 +83,28 @@ class XtextGradleBuilder implements IncrementalXtextBuilder {
}

afterValidate = validator
afterGenerateFile = [source, target|response.generatedFiles.add(new File(target.toFileString))]

afterGenerateFile = [source, target| response.generatedFiles.add(new File(target.toFileString))]
preparResourceSet(containerHandle, state.resourceDescriptions, gradleRequest)
]

val result = doBuild(request, gradleRequest)

if(!validator.isErrorFree) {
if (!validator.isErrorFree) {
throw new GradleException("Xtext validation failed, see build log for details.")
}

val resultingIndex = result.indexState
index.setContainer(containerHandle, resultingIndex.resourceDescriptions)
generatedMappings.put(containerHandle, resultingIndex.fileMappings)
return response
}

private def indexChangedClasspathEntries(GradleBuildRequest gradleRequest) {
val registry = IResourceServiceProvider.Registry.INSTANCE
gradleRequest.dirtyClasspathEntries.filter[exists].forEach [ dirtyClasspathEntry |
gradleRequest.dirtyClasspathEntries.filter[exists].forEach[dirtyClasspathEntry|
val hash = hash(dirtyClasspathEntry)
if(dependencyHashes.get(dirtyClasspathEntry) != hash) {
if (dependencyHashes.get(dirtyClasspathEntry) != hash) {
val containerHandle = dirtyClasspathEntry.path
val request = new BuildRequest => [
indexOnly = true
Expand All @@ -114,128 +113,136 @@ class XtextGradleBuilder implements IncrementalXtextBuilder {
* Only mark files as dirty that have changed in the jar,
* detect the deleted ones and reuse the existing index chunk for unchanged ones.
*/
dirtyFiles += new PathTraverser().findAllResourceUris(dirtyClasspathEntry.path) [ uri |
dirtyFiles += new PathTraverser().findAllResourceUris(dirtyClasspathEntry.path) [uri|
registry.getResourceServiceProvider(uri) !== null
]

afterValidate = [false] // workaround for indexOnly not working in Xtext 2.9.0

afterValidate = [false] //workaround for indexOnly not working in Xtext 2.9.0

val indexChunk = new ResourceDescriptionsData(emptyList)
val fileMappings = new Source2GeneratedMapping
state = new IndexState(indexChunk, fileMappings)
preparResourceSet(containerHandle, indexChunk, gradleRequest)
]

val result = doBuild(request, gradleRequest)
val resultingIndex = result.indexState
index.setContainer(containerHandle, resultingIndex.resourceDescriptions)
dependencyHashes.put(dirtyClasspathEntry, hash)
}
]
}

private def HashCode hash(File file) {
val hasher = Hashing.md5.newHasher
hash(file, hasher)
hasher.hash
}

private def void hash(File file, Hasher hasher) {
if(file.isDirectory) {
if (file.isDirectory) {
file.listFiles.forEach[hash(hasher)]
} else {
Files.asByteSource(file).copyTo(Funnels.asOutputStream(hasher))
}
}

private def preparResourceSet(BuildRequest it, String containerHandle, ResourceDescriptionsData indexChunk, GradleBuildRequest gradleRequest) {
resourceSet = sharedInjector.getInstance(XtextResourceSet) => [
classpathURIContext = gradleRequest.jvmTypesLoader
attachProjectConfig(gradleRequest)
attachGeneratorConfig(gradleRequest)
attachOutputConfig(gradleRequest)
attachPreferences(gradleRequest)
attachJavaConfig(gradleRequest)
attachProjectDescription(containerHandle, gradleRequest.allClasspathEntries.map[path].toList, it)
val contextualIndex = index.createShallowCopyWith(it)
contextualIndex.setContainer(containerHandle, indexChunk)
]
}

private def doBuild(BuildRequest request, GradleBuildRequest gradleRequest) {
try {
val registry = IResourceServiceProvider.Registry.INSTANCE
if(needsCleanBuild(gradleRequest)) {
if (needsCleanBuild(gradleRequest)) {
doClean(gradleRequest)
}
incrementalbuilder.build(request, [uri|registry.getResourceServiceProvider(uri)])
incrementalbuilder.build(request, [uri| registry.getResourceServiceProvider(uri)])
} finally {
cleanup(gradleRequest, request)
}
}

private def doClean(GradleBuildRequest request) {
request.generatorConfigsByLanguage.values.map[outputConfigs].flatten.filter[cleanAutomatically].map[target].forEach [
deleteRecursive
]
request.generatorConfigsByLanguage.values
.map[outputConfigs].flatten
.filter[cleanAutomatically]
.map[target]
.forEach[
deleteRecursive
]
}

private def void deleteRecursive(File file) {
if(file.isDirectory) {
if (file.isDirectory) {
file.listFiles.forEach[deleteRecursive]
}
file.delete
}

private def boolean needsCleanBuild(GradleBuildRequest request) {
!request.incremental || !request.dirtyClasspathEntries.isEmpty || index.getContainer(request.containerHandle) === null
}

private def getJvmTypesLoader(GradleBuildRequest gradleRequest) {
val parent = if(gradleRequest.bootstrapClasspath === null || gradleRequest.bootstrapClasspath.empty) {
ClassLoader.systemClassLoader
} else {
new AlternateJdkLoader(gradleRequest.bootstrapClasspath)
}
val parent = if (gradleRequest.bootstrapClasspath === null || gradleRequest.bootstrapClasspath.empty) {
ClassLoader.systemClassLoader
} else {
new AlternateJdkLoader(gradleRequest.bootstrapClasspath)
}
new URLClassLoader(gradleRequest.allClasspathEntries.map[toURI.toURL], parent)
}

private def cleanup(GradleBuildRequest gradleRequest, BuildRequest request) {
val resourceSet = request.resourceSet
val jvmTypesLoader = resourceSet.classpathURIContext
if(jvmTypesLoader instanceof Closeable) {
if (jvmTypesLoader instanceof Closeable) {
try {
jvmTypesLoader.close
} catch(Exception e) {
} catch (Exception e) {
gradleRequest.logger.debug("Couldn't close jvm types classloader", e)
}
}
resourceSet.resources.clear
resourceSet.eAdapters.clear
}

private def attachProjectConfig(XtextResourceSet resourceSet, GradleBuildRequest gradleRequest) {
ProjectConfigAdapter.install(resourceSet, new GradleProjectConfig(gradleRequest))
}

private def attachProjectDescription(String containerHandle, List<String> dependencies, XtextResourceSet resourceSet) {
new ProjectDescription => [
name = containerHandle
it.dependencies = dependencies
attachToEmfObject(resourceSet)
]
}

private def attachGeneratorConfig(XtextResourceSet resourceSet, GradleBuildRequest gradleRequest) {
new GeneratorConfigProvider.GeneratorConfigAdapter => [
attachToEmfObject(resourceSet)
language2GeneratorConfig.putAll(
gradleRequest.generatorConfigsByLanguage.mapValues [ gradleConfig |
gradleRequest.generatorConfigsByLanguage.mapValues[gradleConfig|
val javaVersion = JavaVersion.fromQualifier(gradleConfig.javaSourceLevel.toString)
if (javaVersion === null) {
gradleRequest.logger.warn("Xtext does not support Java " + gradleConfig.javaSourceLevel.toString + ", falling back to " + JavaVersion.JAVA8.label)
}
new GeneratorConfig => [
generateSyntheticSuppressWarnings = gradleConfig.isGenerateSyntheticSuppressWarnings
generateGeneratedAnnotation = gradleConfig.isGenerateGeneratedAnnotation
includeDateInGeneratedAnnotation = gradleConfig.isIncludeDateInGeneratedAnnotation
includeDateInGeneratedAnnotation = gradleConfig.isIncludeDateInGeneratedAnnotation
generatedAnnotationComment = gradleConfig.generatedAnnotationComment
javaSourceVersion = JavaVersion.fromQualifier(gradleConfig.javaSourceLevel.toString)
javaSourceVersion = javaVersion ?: JavaVersion.JAVA8
]
]
)
Expand All @@ -244,13 +251,10 @@ class XtextGradleBuilder implements IncrementalXtextBuilder {

private def attachOutputConfig(XtextResourceSet resourceSet, GradleBuildRequest gradleRequest) {
resourceSet.eAdapters += new OutputConfigurationAdapter(
gradleRequest.generatorConfigsByLanguage.mapValues [
outputConfigs.map [ gradleOutputConfig |
gradleRequest.generatorConfigsByLanguage.mapValues[
outputConfigs.map[gradleOutputConfig|
new OutputConfiguration(gradleOutputConfig.outletName) => [
outputDirectory = gradleOutputConfig.target.absolutePath
cleanUpDerivedResources = gradleOutputConfig.cleanAutomatically
canClearOutputDirectory = gradleOutputConfig.cleanAutomatically
overrideExistingResources = gradleOutputConfig.cleanAutomatically
]
].toSet
]
Expand All @@ -265,24 +269,11 @@ class XtextGradleBuilder implements IncrementalXtextBuilder {
}
]
}

private def attachJavaConfig(XtextResourceSet resourceSet, GradleBuildRequest gradleRequest) {
try {
val configClass = Class.forName("org.eclipse.xtext.java.resource.JavaConfig")
val javaConfig = configClass.newInstance
val javaVersion = JavaVersion.fromQualifier(gradleRequest.generatorConfigsByLanguage.values.head.javaSourceLevel.toString)
configClass.getMethod("attachToEmfObject", Notifier).invoke(javaConfig, resourceSet)
configClass.getMethod("setJavaSourceLevel", JavaVersion).invoke(javaConfig, javaVersion)
configClass.getMethod("setJavaTargetLevel", JavaVersion).invoke(javaConfig, javaVersion)
} catch(ClassNotFoundException ignore) {
// this only exists in Xtext 2.11 and upwards
}
}


override void installDebugInfo(GradleInstallDebugInfoRequest gradleRequest) {
val request = new InstallDebugInfoRequest => [
classesDir = gradleRequest.classesDir
sourceInstallerByFileExtension = gradleRequest.sourceInstallerByFileExtension.mapValues [ gradleConfig |
sourceInstallerByFileExtension = gradleRequest.sourceInstallerByFileExtension.mapValues[gradleConfig|
new SourceInstallerConfig => [
sourceInstaller = SourceInstaller.valueOf(gradleConfig.sourceInstaller.name)
hideSyntheticVariables = gradleConfig.isHideSyntheticVariables
Expand Down

0 comments on commit 5df47a7

Please sign in to comment.