jps (refactor): reimplement KotlinModuleBuildTarget data binding using CompileContext

Original commit: 9fafe0473c
This commit is contained in:
Sergey Rostov
2018-05-03 14:06:50 +03:00
parent 96725b1e36
commit e4d51df269
11 changed files with 114 additions and 183 deletions
@@ -40,6 +40,7 @@ import org.jetbrains.jps.cmdline.ProjectDescriptor
import org.jetbrains.jps.incremental.*
import org.jetbrains.jps.incremental.messages.BuildMessage
import org.jetbrains.jps.model.JpsModuleRootModificationUtil
import org.jetbrains.jps.model.java.JpsJavaDependencyScope
import org.jetbrains.jps.model.java.JpsJavaExtensionService
import org.jetbrains.jps.util.JpsPathUtil
import org.jetbrains.kotlin.config.IncrementalCompilation
@@ -17,23 +17,19 @@
package org.jetbrains.kotlin.jps.build
import org.jetbrains.jps.builders.JpsBuildTestCase
import org.jetbrains.kotlin.jps.platforms.clearKotlinModuleBuildTargetDataBindings
abstract class BaseKotlinJpsBuildTestCase : JpsBuildTestCase() {
@Throws(Exception::class)
override fun setUp() {
super.setUp()
JpsUtils.resetCaches()
System.setProperty("kotlin.jps.tests", "true")
}
@Throws(Exception::class)
override fun tearDown() {
JpsUtils.resetCaches()
System.clearProperty("kotlin.jps.tests")
super.tearDown()
myModel = null
myBuildParams.clear()
clearKotlinModuleBuildTargetDataBindings()
}
}
@@ -64,9 +64,6 @@ import org.jetbrains.kotlin.jps.model.JpsKotlinCompilerSettings
import org.jetbrains.kotlin.jps.build.KotlinJpsBuildTest.LibraryDependency.*
import org.jetbrains.kotlin.jps.model.kotlinCommonCompilerArguments
import org.jetbrains.kotlin.jps.model.kotlinCompilerArguments
import org.jetbrains.kotlin.jps.platforms.KotlinJsModuleBuildTarget
import org.jetbrains.kotlin.jps.platforms.clearKotlinModuleBuildTargetDataBindings
import org.jetbrains.kotlin.jps.platforms.kotlinData
import org.jetbrains.kotlin.jps.platforms.productionBuildTarget
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils
import org.jetbrains.kotlin.name.FqName
@@ -181,8 +178,6 @@ open class KotlinJpsBuildTest : AbstractKotlinJpsBuildTestCase() {
originalProjectDir = projDirPath.toFile()
workDir = AbstractKotlinJpsBuildTestCase.copyTestDataToTmpDir(originalProjectDir)
orCreateProjectDir
JpsUtils.resetCaches()
}
override fun tearDown() {
@@ -250,7 +245,7 @@ open class KotlinJpsBuildTest : AbstractKotlinJpsBuildTestCase() {
buildAllModules().assertSuccessful()
checkOutputFilesList()
checkWhen(touch("src/test1.kt"), null, k2jsOutput(PROJECT_NAME))
checkWhen(touch("src/test1.kt"), null, pathsToDelete = k2jsOutput(PROJECT_NAME))
}
private fun k2jsOutput(vararg moduleNames: String): Array<String> {
@@ -259,11 +254,11 @@ open class KotlinJpsBuildTest : AbstractKotlinJpsBuildTestCase() {
myProject.modules.forEach {
if (it.name in moduleNamesSet) {
val productionTarget = it.productionBuildTarget.kotlinData as KotlinJsModuleBuildTarget
list.add(toSystemIndependentName(productionTarget.outputFile.relativeTo(workDir).path))
list.add(toSystemIndependentName(productionTarget.outputMetaFile.relativeTo(workDir).path))
val outputDir = it.productionBuildTarget.outputDir!!
list.add(toSystemIndependentName(File("$outputDir/${it.name}.js").relativeTo(workDir).path))
list.add(toSystemIndependentName(File("$outputDir/${it.name}.meta.js").relativeTo(workDir).path))
val kjsmFiles = productionTarget.outputDir.walk()
val kjsmFiles = outputDir.walk()
.filter { it.isFile && it.extension.equals("kjsm", ignoreCase = true) }
list.addAll(kjsmFiles.map { toSystemIndependentName(it.relativeTo(workDir).path) })
@@ -1068,8 +1063,6 @@ open class KotlinJpsBuildTest : AbstractKotlinJpsBuildTestCase() {
}
protected fun checkWhen(actions: Array<Action>, pathsToCompile: Array<String>?, pathsToDelete: Array<String>?) {
clearKotlinModuleBuildTargetDataBindings()
for (action in actions) {
action.apply()
}
@@ -62,8 +62,11 @@ import org.jetbrains.kotlin.config.KotlinCompilerVersion.TEST_IS_PRE_RELEASE_SYS
import org.jetbrains.kotlin.incremental.CacheVersion
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.incremental.withIC
import org.jetbrains.kotlin.jps.JpsKotlinCompilerSettings
import org.jetbrains.kotlin.jps.model.JpsKotlinCompilerSettings
import org.jetbrains.kotlin.jps.build.KotlinJpsBuildTest.LibraryDependency.*
import org.jetbrains.kotlin.jps.model.kotlinCommonCompilerArguments
import org.jetbrains.kotlin.jps.model.kotlinCompilerArguments
import org.jetbrains.kotlin.jps.platforms.productionBuildTarget
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.test.KotlinTestUtils
@@ -174,8 +177,6 @@ open class KotlinJpsBuildTest : AbstractKotlinJpsBuildTestCase() {
originalProjectDir = projDirPath.toFile()
workDir = AbstractKotlinJpsBuildTestCase.copyTestDataToTmpDir(originalProjectDir)
orCreateProjectDir
JpsUtils.resetCaches()
}
override fun tearDown() {
@@ -243,21 +244,26 @@ open class KotlinJpsBuildTest : AbstractKotlinJpsBuildTestCase() {
buildAllModules().assertSuccessful()
checkOutputFilesList()
checkWhen(touch("src/test1.kt"), null, k2jsOutput(PROJECT_NAME))
checkWhen(touch("src/test1.kt"), null, pathsToDelete = k2jsOutput(PROJECT_NAME))
}
private fun k2jsOutput(vararg moduleNames: String): Array<String> {
val list = arrayListOf<String>()
for (moduleName in moduleNames) {
val outputDir = File("out/production/$moduleName")
list.add(toSystemIndependentName(JpsJsModuleUtils.getOutputFile(outputDir, moduleName, false).path))
list.add(toSystemIndependentName(JpsJsModuleUtils.getOutputMetaFile(outputDir, moduleName, false).path))
val moduleNamesSet = moduleNames.toSet()
val list = mutableListOf<String>()
val kjsmFiles = File(workDir, outputDir.path).walk()
.filter { it.isFile && it.extension.equals("kjsm", ignoreCase = true) }
list.addAll(kjsmFiles.map { toSystemIndependentName(it.relativeTo(workDir).path) })
myProject.modules.forEach {
if (it.name in moduleNamesSet) {
val outputDir = it.productionBuildTarget.outputDir!!
list.add(toSystemIndependentName(File("$outputDir/${it.name}.js").relativeTo(workDir).path))
list.add(toSystemIndependentName(File("$outputDir/${it.name}.meta.js").relativeTo(workDir).path))
val kjsmFiles = outputDir.walk()
.filter { it.isFile && it.extension.equals("kjsm", ignoreCase = true) }
list.addAll(kjsmFiles.map { toSystemIndependentName(it.relativeTo(workDir).path) })
}
}
return list.toTypedArray()
}
@@ -515,9 +521,9 @@ open class KotlinJpsBuildTest : AbstractKotlinJpsBuildTestCase() {
assertEquals(1, myProject.modules.size)
val module = myProject.modules.first()
val args = JpsKotlinCompilerSettings.getCommonCompilerArguments(module)
val args = module.kotlinCompilerArguments
args.apiVersion = "1.2"
JpsKotlinCompilerSettings.setCommonCompilerArguments(myProject, args)
myProject.kotlinCommonCompilerArguments = args
buildAllModules().assertSuccessful()
}
@@ -1,92 +0,0 @@
/*
* Copyright 2010-2016 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.kotlin.jps.build;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.TestOnly;
import org.jetbrains.jps.incremental.ModuleBuildTarget;
import org.jetbrains.jps.model.java.JpsJavaClasspathKind;
import org.jetbrains.jps.model.java.JpsJavaDependenciesEnumerator;
import org.jetbrains.jps.model.java.JpsJavaExtensionService;
import org.jetbrains.jps.model.library.JpsLibrary;
import org.jetbrains.jps.model.library.JpsLibraryRoot;
import org.jetbrains.jps.model.library.JpsOrderRootType;
import org.jetbrains.jps.util.JpsPathUtil;
import org.jetbrains.kotlin.config.TargetPlatformKind;
import org.jetbrains.kotlin.jps.model.ModuleSettingsKt;
import org.jetbrains.kotlin.utils.LibraryUtils;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
class JpsUtils {
private static final Map<ModuleBuildTarget, Boolean> IS_KOTLIN_JS_MODULE_CACHE = new ConcurrentHashMap<ModuleBuildTarget, Boolean>();
private static final Map<String, Boolean> IS_KOTLIN_JS_STDLIB_JAR_CACHE = new ConcurrentHashMap<String, Boolean>();
private JpsUtils() {
}
@NotNull
static JpsJavaDependenciesEnumerator getAllDependencies(@NotNull ModuleBuildTarget target) {
return JpsJavaExtensionService.dependencies(target.getModule()).recursively().exportedOnly()
.includedIn(JpsJavaClasspathKind.compile(target.isTests()));
}
static boolean isJsKotlinModule(@NotNull ModuleBuildTarget target) {
Boolean cachedValue = IS_KOTLIN_JS_MODULE_CACHE.get(target);
if (cachedValue != null) return cachedValue;
boolean isKotlinJsModule = isJsKotlinModuleImpl(target);
IS_KOTLIN_JS_MODULE_CACHE.put(target, isKotlinJsModule);
return isKotlinJsModule;
}
private static boolean isJsKotlinModuleImpl(@NotNull ModuleBuildTarget target) {
TargetPlatformKind<?> targetPlatform = ModuleSettingsKt.getTargetPlatform(target.getModule());
if (targetPlatform != null) return targetPlatform == TargetPlatformKind.JavaScript.INSTANCE;
Set<JpsLibrary> libraries = getAllDependencies(target).getLibraries();
for (JpsLibrary library : libraries) {
for (JpsLibraryRoot root : library.getRoots(JpsOrderRootType.COMPILED)) {
String url = root.getUrl();
Boolean cachedValue = IS_KOTLIN_JS_STDLIB_JAR_CACHE.get(url);
if (cachedValue != null) {
if (cachedValue.booleanValue()) {
return true;
}
else {
continue;
}
}
boolean isKotlinJavascriptStdLibrary = LibraryUtils.isKotlinJavascriptStdLibrary(JpsPathUtil.urlToFile(url));
IS_KOTLIN_JS_STDLIB_JAR_CACHE.put(url, isKotlinJavascriptStdLibrary);
if (isKotlinJavascriptStdLibrary) return true;
}
}
return false;
}
@TestOnly
static void resetCaches() {
IS_KOTLIN_JS_MODULE_CACHE.clear();
IS_KOTLIN_JS_STDLIB_JAR_CACHE.clear();
}
}
@@ -57,7 +57,7 @@ import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.jps.model.kotlinCompilerArguments
import org.jetbrains.kotlin.jps.incremental.*
import org.jetbrains.kotlin.jps.platforms.KotlinJsModuleBuildTarget
import org.jetbrains.kotlin.jps.platforms.kotlinData
import org.jetbrains.kotlin.jps.platforms.kotlinBuildTargets
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents
import org.jetbrains.kotlin.name.FqName
@@ -213,7 +213,8 @@ class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) {
val allVersions = cacheVersionsProvider.allVersions(targets)
val actions = allVersions.map { it.checkVersion() }.toMutableSet()
if (chunk.representativeTarget().kotlinData !is KotlinJsModuleBuildTarget) {
val kotlinModuleBuilderTarget = context.kotlinBuildTargets[chunk.representativeTarget()]
if (kotlinModuleBuilderTarget !is KotlinJsModuleBuildTarget) {
val args = compilerArgumentsForChunk(chunk)
val currentBuildMetaInfo = JvmBuildMetaInfo(args)
@@ -309,7 +310,8 @@ class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) {
fsOperations: FSOperationsHelper
): ModuleLevelBuilder.ExitCode {
// Workaround for Android Studio
if (!JavaBuilder.IS_ENABLED[context, true] && !JpsUtils.isJsKotlinModule(chunk.representativeTarget())) {
val isJsModule = context.kotlinBuildTargets[chunk.representativeTarget()] is KotlinJsModuleBuildTarget
if (!JavaBuilder.IS_ENABLED[context, true] && !isJsModule) {
messageCollector.report(INFO, "Kotlin JPS plugin is disabled")
return NOTHING_DONE
}
@@ -377,7 +379,7 @@ class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) {
LOG.info("Compiled successfully")
}
val generatedFiles = getGeneratedFiles(chunk, environment.outputItemsCollector)
val generatedFiles = getGeneratedFiles(context, chunk, environment.outputItemsCollector)
registerOutputItems(outputConsumer, generatedFiles)
saveVersions(context, chunk, commonArguments)
@@ -391,7 +393,9 @@ class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) {
rebuildAfterCacheVersionChanged.clean(target)
}
chunk.representativeTarget().kotlinData?.doAfterBuild()
chunk.targets.forEach {
context.kotlinBuildTargets[it]?.doAfterBuild()
}
updateJavaMappings(chunk, context, dirtyFilesHolder, filesToCompile, generatedFiles, incrementalCaches)
@@ -497,7 +501,8 @@ class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) {
val cacheVersionsProvider = CacheVersionProvider(dataManager.dataPaths)
cacheVersionsProvider.allVersions(targets).forEach { it.saveIfNeeded() }
if (!JpsUtils.isJsKotlinModule(chunk.representativeTarget())) {
val isJsModule = context.kotlinBuildTargets[chunk.representativeTarget()] is KotlinJsModuleBuildTarget
if (!isJsModule) {
val jvmBuildMetaInfo = JvmBuildMetaInfo(commonArguments)
val serializedMetaInfo = JvmBuildMetaInfo.serializeToString(jvmBuildMetaInfo)
@@ -549,9 +554,10 @@ class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) {
}
}
val isDoneSomething = representativeTarget.kotlinData?.compileModuleChunk(
allCompiledFiles, chunk, commonArguments, context,
dirtyFilesHolder, environment, filesToCompile, fsOperations
val kotlinModuleBuilderTarget = context.kotlinBuildTargets[representativeTarget]
val isDoneSomething = kotlinModuleBuilderTarget?.compileModuleChunk(
allCompiledFiles, chunk, commonArguments, dirtyFilesHolder,
environment, filesToCompile, fsOperations
) ?: false
return if (isDoneSomething) environment.outputItemsCollector else null
@@ -567,7 +573,7 @@ class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) {
register(LookupTracker::class.java, lookupTracker)
register(
IncrementalCompilationComponents::class.java,
IncrementalCompilationComponentsImpl(incrementalCaches.mapKeys { it.key.kotlinData!!.targetId })
IncrementalCompilationComponentsImpl(incrementalCaches.mapKeys { context.kotlinBuildTargets[it.key]!!.targetId })
)
register(CompilationCanceledStatus::class.java, object : CompilationCanceledStatus {
override fun checkCanceled() {
@@ -617,6 +623,7 @@ class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) {
}
private fun getGeneratedFiles(
context: CompileContext,
chunk: ModuleChunk,
outputItemCollector: OutputItemsCollectorImpl
): Map<ModuleBuildTarget, List<GeneratedFile>> {
@@ -624,7 +631,7 @@ class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) {
val sourceToTarget = HashMap<File, ModuleBuildTarget>()
if (chunk.targets.size > 1) {
for (target in chunk.targets) {
target.kotlinData?.sources?.forEach {
context.kotlinBuildTargets[target]?.sources?.forEach {
sourceToTarget[it] = target
}
}
@@ -9,6 +9,7 @@ import com.intellij.util.containers.MultiMap
import org.jetbrains.jps.ModuleChunk
import org.jetbrains.jps.builders.DirtyFilesHolder
import org.jetbrains.jps.builders.java.JavaSourceRootDescriptor
import com.intellij.openapi.compiler.CompileContext as JpsCompileContext
import org.jetbrains.jps.incremental.CompileContext
import org.jetbrains.jps.incremental.FSOperations
import org.jetbrains.jps.incremental.ModuleBuildTarget
@@ -21,14 +22,13 @@ import org.jetbrains.kotlin.jps.model.k2MetadataCompilerArguments
import org.jetbrains.kotlin.jps.model.kotlinCompilerSettings
import java.io.File
class KotlinCommonModuleBuildTarget(jpsModuleBuildTarget: ModuleBuildTarget) :
KotlinModuleBuilderTarget(jpsModuleBuildTarget) {
class KotlinCommonModuleBuildTarget(compileContext: CompileContext, jpsModuleBuildTarget: ModuleBuildTarget) :
KotlinModuleBuilderTarget(compileContext, jpsModuleBuildTarget) {
override fun compileModuleChunk(
allCompiledFiles: MutableSet<File>,
chunk: ModuleChunk,
commonArguments: CommonCompilerArguments,
context: CompileContext,
dirtyFilesHolder: DirtyFilesHolder<JavaSourceRootDescriptor, ModuleBuildTarget>,
environment: JpsCompilerEnvironment,
filesToCompile: MultiMap<ModuleBuildTarget, File>,
@@ -28,12 +28,13 @@ import org.jetbrains.kotlin.utils.KotlinJavascriptMetadataUtils.META_JS_SUFFIX
import java.io.File
import java.net.URI
class KotlinJsModuleBuildTarget(jpsModuleBuildTarget: ModuleBuildTarget) : KotlinModuleBuilderTarget(jpsModuleBuildTarget) {
class KotlinJsModuleBuildTarget(compileContext: CompileContext, jpsModuleBuildTarget: ModuleBuildTarget) :
KotlinModuleBuilderTarget(compileContext, jpsModuleBuildTarget) {
override fun compileModuleChunk(
allCompiledFiles: MutableSet<File>,
chunk: ModuleChunk,
commonArguments: CommonCompilerArguments,
context: CompileContext,
dirtyFilesHolder: DirtyFilesHolder<JavaSourceRootDescriptor, ModuleBuildTarget>,
environment: JpsCompilerEnvironment,
filesToCompile: MultiMap<ModuleBuildTarget, File>,
@@ -139,7 +140,7 @@ class KotlinJsModuleBuildTarget(jpsModuleBuildTarget: ModuleBuildTarget) : Kotli
result: MutableList<String>,
isTests: Boolean
) {
val dependencyBuildTarget = ModuleBuildTarget(module, isTests).kotlinData
val dependencyBuildTarget = context.kotlinBuildTargets[ModuleBuildTarget(module, isTests)]
if (dependencyBuildTarget != this@KotlinJsModuleBuildTarget &&
dependencyBuildTarget is KotlinJsModuleBuildTarget &&
@@ -34,12 +34,13 @@ import org.jetbrains.kotlin.modules.KotlinModuleXmlBuilder
import java.io.File
import java.io.IOException
class KotlinJvmModuleBuildTarget(jpsModuleBuildTarget: ModuleBuildTarget) : KotlinModuleBuilderTarget(jpsModuleBuildTarget) {
class KotlinJvmModuleBuildTarget(compileContext: CompileContext, jpsModuleBuildTarget: ModuleBuildTarget) :
KotlinModuleBuilderTarget(compileContext, jpsModuleBuildTarget) {
override fun compileModuleChunk(
allCompiledFiles: MutableSet<File>,
chunk: ModuleChunk,
commonArguments: CommonCompilerArguments,
context: CompileContext,
dirtyFilesHolder: DirtyFilesHolder<JavaSourceRootDescriptor, ModuleBuildTarget>,
environment: JpsCompilerEnvironment,
filesToCompile: MultiMap<ModuleBuildTarget, File>,
@@ -111,7 +112,7 @@ class KotlinJvmModuleBuildTarget(jpsModuleBuildTarget: ModuleBuildTarget) : Kotl
var noSources = true
val targets = chunk.targets.mapNotNull { it.kotlinData as? KotlinJvmModuleBuildTarget }
val targets = chunk.targets.mapNotNull { this.context.kotlinBuildTargets[it] as? KotlinJvmModuleBuildTarget }
val outputDirs = targets.map { it.outputDir }.toSet()
@@ -32,7 +32,7 @@ import java.io.File
/**
* Properties and actions for Kotlin test / production module build target.
*/
abstract class KotlinModuleBuilderTarget(val jpsModuleBuildTarget: ModuleBuildTarget) {
abstract class KotlinModuleBuilderTarget(val context: CompileContext, val jpsModuleBuildTarget: ModuleBuildTarget) {
val module: JpsModule
get() = jpsModuleBuildTarget.module
@@ -66,8 +66,8 @@ abstract class KotlinModuleBuilderTarget(val jpsModuleBuildTarget: ModuleBuildTa
val result = mutableListOf<KotlinModuleBuilderTarget>()
if (isTests) {
result.addIfNotNull(module.productionBuildTarget.kotlinData)
result.addIfNotNull(relatedProductionModule?.productionBuildTarget?.kotlinData)
result.addIfNotNull(context.kotlinBuildTargets[module.productionBuildTarget])
result.addIfNotNull(context.kotlinBuildTargets[relatedProductionModule?.productionBuildTarget])
}
return result.filter { it.sources.isNotEmpty() }
@@ -95,7 +95,7 @@ abstract class KotlinModuleBuilderTarget(val jpsModuleBuildTarget: ModuleBuildTa
return allDependencies.modules
.filter { it.name in implementedModuleNames }
.map { ModuleBuildTarget(it, isTests).kotlinData!! }
.map { context.kotlinBuildTargets[ModuleBuildTarget(it, isTests)]!! }
}
val sources by lazy {
@@ -134,7 +134,6 @@ abstract class KotlinModuleBuilderTarget(val jpsModuleBuildTarget: ModuleBuildTa
allCompiledFiles: MutableSet<File>,
chunk: ModuleChunk,
commonArguments: CommonCompilerArguments,
context: CompileContext,
dirtyFilesHolder: DirtyFilesHolder<JavaSourceRootDescriptor, ModuleBuildTarget>,
environment: JpsCompilerEnvironment,
filesToCompile: MultiMap<ModuleBuildTarget, File>,
@@ -5,8 +5,9 @@
package org.jetbrains.kotlin.jps.platforms
import org.jetbrains.annotations.TestOnly
import com.intellij.openapi.util.Key
import org.jetbrains.jps.builders.java.JavaModuleBuildTargetType
import org.jetbrains.jps.incremental.CompileContext
import org.jetbrains.jps.incremental.ModuleBuildTarget
import org.jetbrains.jps.model.java.JpsJavaModuleType
import org.jetbrains.jps.model.library.JpsOrderRootType
@@ -26,50 +27,68 @@ val JpsModule.productionBuildTarget
val JpsModule.testBuildTarget
get() = ModuleBuildTarget(this, true)
private val kotlinBuildTargetsData = ConcurrentHashMap<ModuleBuildTarget, KotlinModuleBuilderTarget>()
private val kotlinBuildTargetsCompileContextKey = Key<KotlinBuildTargets>("kotlinBuildTargets")
val ModuleBuildTarget.kotlinData: KotlinModuleBuilderTarget?
val CompileContext.kotlinBuildTargets: KotlinBuildTargets
get() {
if (module.moduleType != JpsJavaModuleType.INSTANCE) return null
val value = getUserData(kotlinBuildTargetsCompileContextKey)
if (value != null) return value
return kotlinBuildTargetsData.computeIfAbsent(this) {
when (module.targetPlatform ?: detectTargetPlatform()) {
is TargetPlatformKind.Common -> KotlinCommonModuleBuildTarget(this)
is TargetPlatformKind.JavaScript -> KotlinJsModuleBuildTarget(this)
is TargetPlatformKind.Jvm -> KotlinJvmModuleBuildTarget(this)
synchronized(this) {
val actualValue = getUserData(kotlinBuildTargetsCompileContextKey)
if (actualValue != null) return actualValue
val newValue = KotlinBuildTargets(this)
putUserData(kotlinBuildTargetsCompileContextKey, newValue)
return newValue
}
}
class KotlinBuildTargets internal constructor(val compileContext: CompileContext) {
private val byJpsModuleBuildTarget = ConcurrentHashMap<ModuleBuildTarget, KotlinModuleBuilderTarget>()
private val isKotlinJsStdlibJar = ConcurrentHashMap<String, Boolean>()
@JvmName("getNullable")
operator fun get(target: ModuleBuildTarget?): KotlinModuleBuilderTarget? {
if (target == null) return null
return get(target)
}
operator fun get(target: ModuleBuildTarget): KotlinModuleBuilderTarget? {
if (target.module.moduleType != JpsJavaModuleType.INSTANCE) return null
return byJpsModuleBuildTarget.computeIfAbsent(target) {
when (target.module.targetPlatform ?: detectTargetPlatform(target)) {
is TargetPlatformKind.Common -> KotlinCommonModuleBuildTarget(compileContext, target)
is TargetPlatformKind.JavaScript -> KotlinJsModuleBuildTarget(compileContext, target)
is TargetPlatformKind.Jvm -> KotlinJvmModuleBuildTarget(compileContext, target)
}
}
}
/**
* Compatibility for KT-14082
* todo: remove when all projects migrated to facets
*/
private fun ModuleBuildTarget.detectTargetPlatform(): TargetPlatformKind<*> {
if (hasJsStdLib()) return TargetPlatformKind.JavaScript
/**
* Compatibility for KT-14082
* todo: remove when all projects migrated to facets
*/
private fun detectTargetPlatform(target: ModuleBuildTarget): TargetPlatformKind<*> {
if (hasJsStdLib(target)) return TargetPlatformKind.JavaScript
return TargetPlatformKind.DEFAULT_PLATFORM
}
private val IS_KOTLIN_JS_STDLIB_JAR_CACHE = ConcurrentHashMap<String, Boolean>()
private fun ModuleBuildTarget.hasJsStdLib(): Boolean {
KotlinJvmModuleBuildTarget(this).allDependencies.libraries.forEach { library ->
for (root in library.getRoots(JpsOrderRootType.COMPILED)) {
val url = root.url
val isKotlinJsLib = IS_KOTLIN_JS_STDLIB_JAR_CACHE.computeIfAbsent(url) {
LibraryUtils.isKotlinJavascriptStdLibrary(JpsPathUtil.urlToFile(url))
}
if (isKotlinJsLib) return true
}
return TargetPlatformKind.DEFAULT_PLATFORM
}
return false
}
private fun hasJsStdLib(target: ModuleBuildTarget): Boolean {
KotlinJvmModuleBuildTarget(compileContext, target).allDependencies.libraries.forEach { library ->
for (root in library.getRoots(JpsOrderRootType.COMPILED)) {
val url = root.url
@TestOnly
internal fun clearKotlinModuleBuildTargetDataBindings() {
kotlinBuildTargetsData.clear()
val isKotlinJsLib = isKotlinJsStdlibJar.computeIfAbsent(url) {
LibraryUtils.isKotlinJavascriptStdLibrary(JpsPathUtil.urlToFile(url))
}
if (isKotlinJsLib) return true
}
}
return false
}
}