external build tests: workaround to get rid of ClassNotFoundException from ServiceLoader when Kotlin plugin isn't installed

This commit is contained in:
nik
2014-12-04 15:23:34 +03:00
parent 3b501a1706
commit 1bd826094e
2 changed files with 132 additions and 94 deletions
@@ -0,0 +1,44 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jps.builders.java;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.incremental.BuilderService;
import org.jetbrains.jps.incremental.ModuleLevelBuilder;
import java.util.Collections;
import java.util.List;
/**
* @author nik
*/
public class MockPackageFacadeBuilderService extends BuilderService {
@NotNull
@Override
public List<? extends ModuleLevelBuilder> createModuleLevelBuilders() {
//todo[nik] this is a temporary solution until all team members have Kotlin plugin installed
try {
Class<?> aClass = Class.forName("org.jetbrains.jps.builders.java.MockPackageFacadeGenerator");
return Collections.singletonList((ModuleLevelBuilder)aClass.newInstance());
}
catch (ClassNotFoundException e) {
return Collections.emptyList();
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@@ -44,103 +44,97 @@ import com.intellij.util.io.EnumeratorStringDescriptor
*
* @author nik
*/
public class MockPackageFacadeBuilderService: BuilderService() {
override fun createModuleLevelBuilders(): List<ModuleLevelBuilder> {
return listOf(MockPackageFacadeGenerator())
class MockPackageFacadeGenerator : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) {
override fun build(context: CompileContext,
chunk: ModuleChunk,
dirtyFilesHolder: DirtyFilesHolder<JavaSourceRootDescriptor, ModuleBuildTarget>,
outputConsumer: ModuleLevelBuilder.OutputConsumer): ModuleLevelBuilder.ExitCode {
val filesToCompile = MultiMap.createLinked<ModuleBuildTarget, File>()
dirtyFilesHolder.processDirtyFiles { target, file, root ->
if (isCompilable(file)) {
filesToCompile.putValue(target, file)
}
true
}
val allFilesToCompile = ArrayList(filesToCompile.values())
if (allFilesToCompile.isEmpty()) return ModuleLevelBuilder.ExitCode.NOTHING_DONE
if (JavaBuilderUtil.isCompileJavaIncrementally(context)) {
val logger = context.getLoggingManager().getProjectBuilderLogger()
if (logger.isEnabled()) {
if (!filesToCompile.isEmpty()) {
logger.logCompiledFiles(allFilesToCompile, "MockPackageFacadeGenerator", "Compiling files:")
}
}
}
val mappings = context.getProjectDescriptor().dataManager.getMappings()
val delta = mappings.createDelta()
val callback = delta.getCallback()
fun generateClass(packageName: String, className: String, target: ModuleBuildTarget, sources: Collection<String>, generate: (ClassWriter.() -> Unit)? = null) {
val writer = ClassWriter(ClassWriter.COMPUTE_FRAMES)
val fullClassName = StringUtil.getQualifiedName(packageName, className).replace('.', '/')
writer.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC, fullClassName, null, "java/lang/Object", null)
if (generate != null) {
writer.generate()
}
writer.visitEnd()
val outputFile = File(target.getOutputDir(), "$fullClassName.class")
val classBytes = writer.toByteArray()
FileUtil.writeToFile(outputFile, classBytes)
outputConsumer.registerOutputFile(target, outputFile, sources)
callback.associate(fullClassName.replace('/', '.'), sources, ClassReader(classBytes))
}
for (target in chunk.getTargets()) {
val packagesStorage = context.getProjectDescriptor().dataManager.getStorage(target, PACKAGE_CACHE_STORAGE_PROVIDER)
for (file in filesToCompile[target]) {
generateClass(getPackageName(file), FileUtil.getNameWithoutExtension(file), target, listOf(file.getAbsolutePath()))
}
val packagesToGenerate = filesToCompile[target].mapTo(THashSet<String>(), ::getPackageName)
filesToCompile[target].mapNotNullTo(packagesToGenerate) { packagesStorage.getState(it.getAbsolutePath()) }
val packagesFromDeletedFiles = dirtyFilesHolder.getRemovedFiles(target).filter { isCompilable(File(it)) }.mapNotNull { packagesStorage.getState(it) }
packagesToGenerate.addAll(packagesFromDeletedFiles)
val getParentFile: (File) -> File = { it.getParentFile() }
val dirsToCheck = filesToCompile[target].mapTo(THashSet(FileUtil.FILE_HASHING_STRATEGY), getParentFile)
packagesFromDeletedFiles.flatMap { mappings.getClassSources(mappings.getName(StringUtil.getQualifiedName(it, "PackageFacade"))) }.mapNotNullTo(dirsToCheck, getParentFile)
for (packageName in packagesToGenerate) {
val files = dirsToCheck.mapNotNull { it.listFiles() }.flatMap { it.toList() }.filter { isCompilable(it) && packageName == getPackageName(it) }
if (files.isEmpty()) continue
val classNames = files.map { FileUtilRt.getNameWithoutExtension(it.getName()) }.sort()
val sources = files.map { it.getAbsolutePath() }
generateClass(packageName, "PackageFacade", target, sources) {
for (fileName in classNames) {
val fieldClass = StringUtil.getQualifiedName(packageName, fileName).replace('.', '/')
visitField(Opcodes.ACC_PUBLIC, StringUtil.decapitalize(fileName), "L$fieldClass;", null, null).visitEnd()
}
}
for (source in sources) {
packagesStorage.update(FileUtil.toSystemIndependentName(source), packageName)
}
}
}
if (JavaBuilderUtil.updateMappings(context, delta, dirtyFilesHolder, chunk, allFilesToCompile, allFilesToCompile)) {
return ModuleLevelBuilder.ExitCode.ADDITIONAL_PASS_REQUIRED
}
return ModuleLevelBuilder.ExitCode.OK
}
private class MockPackageFacadeGenerator: ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) {
override fun build(context: CompileContext,
chunk: ModuleChunk,
dirtyFilesHolder: DirtyFilesHolder<JavaSourceRootDescriptor, ModuleBuildTarget>,
outputConsumer: ModuleLevelBuilder.OutputConsumer): ModuleLevelBuilder.ExitCode {
val filesToCompile = MultiMap.createLinked<ModuleBuildTarget, File>()
dirtyFilesHolder.processDirtyFiles { target, file, root ->
if (isCompilable(file)) {
filesToCompile.putValue(target, file)
}
true
}
override fun getCompilableFileExtensions(): List<String> {
return listOf("p")
}
val allFilesToCompile = ArrayList(filesToCompile.values())
if (allFilesToCompile.isEmpty()) return ModuleLevelBuilder.ExitCode.NOTHING_DONE
if (JavaBuilderUtil.isCompileJavaIncrementally(context)) {
val logger = context.getLoggingManager().getProjectBuilderLogger()
if (logger.isEnabled()) {
if (!filesToCompile.isEmpty()) {
logger.logCompiledFiles(allFilesToCompile, "MockPackageFacadeGenerator", "Compiling files:")
}
}
}
val mappings = context.getProjectDescriptor().dataManager.getMappings()
val delta = mappings.createDelta()
val callback = delta.getCallback()
fun generateClass(packageName: String, className: String, target: ModuleBuildTarget, sources: Collection<String>, generate: (ClassWriter.() -> Unit)? = null) {
val writer = ClassWriter(ClassWriter.COMPUTE_FRAMES)
val fullClassName = StringUtil.getQualifiedName(packageName, className).replace('.', '/')
writer.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC, fullClassName, null, "java/lang/Object", null)
if (generate != null) {
writer.generate()
}
writer.visitEnd()
val outputFile = File(target.getOutputDir(), "$fullClassName.class")
val classBytes = writer.toByteArray()
FileUtil.writeToFile(outputFile, classBytes)
outputConsumer.registerOutputFile(target, outputFile, sources)
callback.associate(fullClassName.replace('/', '.'), sources, ClassReader(classBytes))
}
for (target in chunk.getTargets()) {
val packagesStorage = context.getProjectDescriptor().dataManager.getStorage(target, PACKAGE_CACHE_STORAGE_PROVIDER)
for (file in filesToCompile[target]) {
generateClass(getPackageName(file), FileUtil.getNameWithoutExtension(file), target, listOf(file.getAbsolutePath()))
}
val packagesToGenerate = filesToCompile[target].mapTo(THashSet<String>(), ::getPackageName)
filesToCompile[target].mapNotNullTo(packagesToGenerate) { packagesStorage.getState(it.getAbsolutePath()) }
val packagesFromDeletedFiles = dirtyFilesHolder.getRemovedFiles(target).filter { isCompilable(File(it)) }.mapNotNull { packagesStorage.getState(it) }
packagesToGenerate.addAll(packagesFromDeletedFiles)
val getParentFile: (File) -> File = { it.getParentFile() }
val dirsToCheck = filesToCompile[target].mapTo(THashSet(FileUtil.FILE_HASHING_STRATEGY), getParentFile)
packagesFromDeletedFiles.flatMap { mappings.getClassSources(mappings.getName(StringUtil.getQualifiedName(it, "PackageFacade"))) }.mapNotNullTo(dirsToCheck, getParentFile)
for (packageName in packagesToGenerate) {
val files = dirsToCheck.mapNotNull { it.listFiles() }.flatMap { it.toList() }.filter { isCompilable(it) && packageName == getPackageName(it) }
if (files.isEmpty()) continue
val classNames = files.map { FileUtilRt.getNameWithoutExtension(it.getName()) }.sort()
val sources = files.map { it.getAbsolutePath() }
generateClass(packageName, "PackageFacade", target, sources) {
for (fileName in classNames) {
val fieldClass = StringUtil.getQualifiedName(packageName, fileName).replace('.', '/')
visitField(Opcodes.ACC_PUBLIC, StringUtil.decapitalize(fileName), "L$fieldClass;", null, null).visitEnd()
}
}
for (source in sources) {
packagesStorage.update(FileUtil.toSystemIndependentName(source), packageName)
}
}
}
if (JavaBuilderUtil.updateMappings(context, delta, dirtyFilesHolder, chunk, allFilesToCompile, allFilesToCompile)) {
return ModuleLevelBuilder.ExitCode.ADDITIONAL_PASS_REQUIRED
}
return ModuleLevelBuilder.ExitCode.OK
}
override fun getCompilableFileExtensions(): List<String> {
return listOf("p")
}
override fun getPresentableName(): String {
return "Mock Package Facade Generator"
}
override fun getPresentableName(): String {
return "Mock Package Facade Generator"
}
}