[BTA tests] Implement basic infrastructure for compilation tests
^KT-61860 In Progress
This commit is contained in:
committed by
Space Team
parent
90fee75eba
commit
c952d74f7c
@@ -15,6 +15,8 @@ dependencies {
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
optIn.add("org.jetbrains.kotlin.buildtools.api.ExperimentalBuildToolsApi")
|
||||
optIn.add("kotlin.ExperimentalStdlibApi")
|
||||
optIn.add("kotlin.io.path.ExperimentalPathApi")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.buildtools.api.tests.compilation.model
|
||||
|
||||
import java.nio.file.Path
|
||||
|
||||
abstract class AbstractModule(
|
||||
val project: Project,
|
||||
override val moduleName: String,
|
||||
val moduleDirectory: Path,
|
||||
val dependencies: List<Dependency>,
|
||||
override val additionalCompilationArguments: List<String> = emptyList(),
|
||||
) : Module {
|
||||
override val sourcesDirectory: Path
|
||||
get() = moduleDirectory.resolve("src")
|
||||
|
||||
override val buildDirectory: Path
|
||||
get() = moduleDirectory.resolve("build")
|
||||
|
||||
override val outputDirectory: Path
|
||||
get() = buildDirectory.resolve("output")
|
||||
|
||||
override val location: Path
|
||||
get() = outputDirectory
|
||||
|
||||
override val icWorkingDir: Path
|
||||
get() = buildDirectory.resolve("ic")
|
||||
|
||||
override val snapshotFile: Path
|
||||
get() = icWorkingDir.resolve("$moduleName.snapshot")
|
||||
|
||||
override val icCachesDir: Path
|
||||
get() = icWorkingDir.resolve("caches")
|
||||
|
||||
override fun toString() = moduleName
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.buildtools.api.tests.compilation.model
|
||||
|
||||
import org.junit.jupiter.api.io.TempDir
|
||||
import java.nio.file.Path
|
||||
|
||||
abstract class BaseCompilationTest {
|
||||
@TempDir
|
||||
lateinit var workingDirectory: Path
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.buildtools.api.tests.compilation.model
|
||||
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
import org.junit.jupiter.params.provider.ArgumentsSource
|
||||
|
||||
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@ParameterizedTest(name = "{0}: {displayName}")
|
||||
@ArgumentsSource(
|
||||
DefaultStrategyAgnosticCompilationTestArgumentProvider::class
|
||||
)
|
||||
annotation class DefaultStrategyAgnosticCompilationTest
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.buildtools.api.tests.compilation.model
|
||||
|
||||
import org.jetbrains.kotlin.buildtools.api.CompilationService
|
||||
import org.junit.jupiter.api.Named.named
|
||||
import org.junit.jupiter.api.extension.ExtensionContext
|
||||
import org.junit.jupiter.params.provider.Arguments
|
||||
import org.junit.jupiter.params.provider.ArgumentsProvider
|
||||
import java.util.stream.Stream
|
||||
import kotlin.streams.asStream
|
||||
|
||||
class DefaultStrategyAgnosticCompilationTestArgumentProvider : ArgumentsProvider {
|
||||
private val compilationService = CompilationService.loadImplementation(this.javaClass.classLoader)
|
||||
|
||||
override fun provideArguments(context: ExtensionContext): Stream<out Arguments> {
|
||||
return sequenceOf(
|
||||
named("in-process", compilationService.makeCompilerExecutionStrategyConfiguration().useInProcessStrategy()),
|
||||
named("within daemon", compilationService.makeCompilerExecutionStrategyConfiguration().useDaemonStrategy(emptyList())),
|
||||
).map { Arguments.of(it) }.asStream()
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.buildtools.api.tests.compilation.model
|
||||
|
||||
import java.nio.file.Path
|
||||
|
||||
interface Dependency {
|
||||
val location: Path
|
||||
val snapshotFile: Path
|
||||
}
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.buildtools.api.tests.compilation.model
|
||||
|
||||
import org.jetbrains.kotlin.buildtools.api.CompilationResult
|
||||
import org.jetbrains.kotlin.buildtools.api.CompilationService
|
||||
import org.jetbrains.kotlin.buildtools.api.CompilerExecutionStrategyConfiguration
|
||||
import org.jetbrains.kotlin.buildtools.api.SourcesChanges
|
||||
import org.jetbrains.kotlin.buildtools.api.jvm.AccessibleClassSnapshot
|
||||
import org.jetbrains.kotlin.buildtools.api.jvm.ClassSnapshotGranularity
|
||||
import org.jetbrains.kotlin.buildtools.api.jvm.ClasspathSnapshotBasedIncrementalCompilationApproachParameters
|
||||
import org.jetbrains.kotlin.buildtools.api.jvm.JvmCompilationConfiguration
|
||||
import org.jetbrains.kotlin.buildtools.api.tests.buildToolsVersion
|
||||
import org.jetbrains.kotlin.tooling.core.KotlinToolingVersion
|
||||
import java.io.File
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.absolutePathString
|
||||
import kotlin.io.path.createParentDirectories
|
||||
import kotlin.io.path.listDirectoryEntries
|
||||
import kotlin.io.path.toPath
|
||||
|
||||
class JvmModule(
|
||||
project: Project,
|
||||
moduleName: String,
|
||||
moduleDirectory: Path,
|
||||
dependencies: List<Dependency>,
|
||||
additionalCompilationArguments: List<String> = emptyList(),
|
||||
) : AbstractModule(
|
||||
project,
|
||||
moduleName,
|
||||
moduleDirectory,
|
||||
dependencies,
|
||||
additionalCompilationArguments,
|
||||
) {
|
||||
private val compilationService = CompilationService.loadImplementation(this.javaClass.classLoader)
|
||||
|
||||
override fun compile(
|
||||
strategyConfig: CompilerExecutionStrategyConfiguration,
|
||||
compilationConfigAction: (JvmCompilationConfiguration) -> Unit,
|
||||
): CompilationResult {
|
||||
val stdlibLocation =
|
||||
KotlinVersion::class.java.protectionDomain.codeSource.location.toURI().toPath() // compile against the provided stdlib
|
||||
val dependencyFiles = dependencies.map { it.location }.plusElement(stdlibLocation)
|
||||
val compilationConfig = compilationService.makeJvmCompilationConfiguration()
|
||||
compilationConfigAction(compilationConfig)
|
||||
val defaultCompilationArguments = listOf(
|
||||
"-no-reflect",
|
||||
"-no-stdlib",
|
||||
"-d", outputDirectory.absolutePathString(),
|
||||
"-cp", dependencyFiles.joinToString(File.pathSeparator),
|
||||
"-module-name", moduleName,
|
||||
)
|
||||
return compilationService.compileJvm(
|
||||
project.projectId,
|
||||
strategyConfig,
|
||||
compilationConfig,
|
||||
sourcesDirectory.listDirectoryEntries().map { it.toFile() },
|
||||
defaultCompilationArguments + additionalCompilationArguments,
|
||||
)
|
||||
}
|
||||
|
||||
private fun generateClasspathSnapshot(dependency: Dependency): Path {
|
||||
val snapshot =
|
||||
compilationService.calculateClasspathSnapshot(dependency.location.toFile(), ClassSnapshotGranularity.CLASS_MEMBER_LEVEL)
|
||||
val hash = snapshot.classSnapshots.values
|
||||
.filterIsInstance<AccessibleClassSnapshot>()
|
||||
.withIndex()
|
||||
.sumOf { (index, snapshot) -> index * 31 + snapshot.classAbiHash }
|
||||
// see details in docs for `CachedClasspathSnapshotSerializer` for details why we can't use a fixed name
|
||||
val snapshotFile = icWorkingDir.resolve("dep-$hash.snapshot")
|
||||
snapshotFile.createParentDirectories()
|
||||
snapshot.saveSnapshot(snapshotFile.toFile())
|
||||
return snapshotFile
|
||||
}
|
||||
|
||||
override fun compileIncrementally(
|
||||
strategyConfig: CompilerExecutionStrategyConfiguration,
|
||||
sourcesChanges: SourcesChanges,
|
||||
forceNonIncrementalCompilation: Boolean,
|
||||
compilationConfigAction: (JvmCompilationConfiguration) -> Unit,
|
||||
): CompilationResult {
|
||||
return compile(strategyConfig) { compilationConfig ->
|
||||
val snapshots = dependencies.map {
|
||||
generateClasspathSnapshot(it).toFile()
|
||||
}
|
||||
val shrunkClasspathSnapshotFile = icWorkingDir.resolve("shrunk-classpath-snapshot.bin")
|
||||
val params = ClasspathSnapshotBasedIncrementalCompilationApproachParameters(
|
||||
snapshots,
|
||||
shrunkClasspathSnapshotFile.toFile()
|
||||
)
|
||||
|
||||
val options = compilationConfig.makeClasspathSnapshotBasedIncrementalCompilationConfiguration()
|
||||
options.setBuildDir(buildDirectory.toFile())
|
||||
options.setRootProjectDir(project.projectDirectory.toFile())
|
||||
|
||||
if (buildToolsVersion < KotlinToolingVersion(2, 0, 0, "Beta2")) {
|
||||
// workaround for the incorrect default value
|
||||
options.useOutputDirs(setOf(icCachesDir.toFile(), outputDirectory.toFile()))
|
||||
}
|
||||
|
||||
if (forceNonIncrementalCompilation) {
|
||||
options.forceNonIncrementalMode()
|
||||
}
|
||||
|
||||
compilationConfig.useIncrementalCompilation(
|
||||
icCachesDir.toFile(),
|
||||
sourcesChanges,
|
||||
params,
|
||||
options,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.buildtools.api.tests.compilation.model
|
||||
|
||||
import org.jetbrains.kotlin.buildtools.api.CompilationResult
|
||||
import org.jetbrains.kotlin.buildtools.api.CompilerExecutionStrategyConfiguration
|
||||
import org.jetbrains.kotlin.buildtools.api.SourcesChanges
|
||||
import org.jetbrains.kotlin.buildtools.api.jvm.JvmCompilationConfiguration
|
||||
import java.nio.file.Path
|
||||
|
||||
interface Module : Dependency {
|
||||
val moduleName: String
|
||||
val additionalCompilationArguments: List<String>
|
||||
val sourcesDirectory: Path
|
||||
val buildDirectory: Path
|
||||
val outputDirectory: Path
|
||||
val icWorkingDir: Path
|
||||
val icCachesDir: Path
|
||||
|
||||
fun compile(
|
||||
strategyConfig: CompilerExecutionStrategyConfiguration,
|
||||
compilationConfigAction: (JvmCompilationConfiguration) -> Unit = {},
|
||||
): CompilationResult
|
||||
|
||||
fun compileIncrementally(
|
||||
strategyConfig: CompilerExecutionStrategyConfiguration,
|
||||
sourcesChanges: SourcesChanges,
|
||||
forceNonIncrementalCompilation: Boolean = false,
|
||||
compilationConfigAction: (JvmCompilationConfiguration) -> Unit = {},
|
||||
): CompilationResult
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.buildtools.api.tests.compilation.model
|
||||
|
||||
import org.jetbrains.kotlin.buildtools.api.ProjectId
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
import java.util.*
|
||||
import kotlin.io.path.copyToRecursively
|
||||
import kotlin.io.path.createDirectories
|
||||
import kotlin.io.path.isDirectory
|
||||
|
||||
class Project(
|
||||
val projectDirectory: Path,
|
||||
) {
|
||||
val projectId = ProjectId.ProjectUUID(UUID.randomUUID())
|
||||
|
||||
fun module(
|
||||
moduleName: String,
|
||||
dependencies: List<Module> = emptyList(),
|
||||
additionalCompilationArguments: List<String> = emptyList(),
|
||||
): Module {
|
||||
val moduleDirectory = projectDirectory.resolve(moduleName)
|
||||
val module = JvmModule(this, moduleName, moduleDirectory, dependencies, additionalCompilationArguments)
|
||||
module.sourcesDirectory.createDirectories()
|
||||
val templatePath = Paths.get("src/testCommon/resources/modules/$moduleName")
|
||||
assert(templatePath.isDirectory()) {
|
||||
"Template for $moduleName not found. Expected template directory path is $templatePath"
|
||||
}
|
||||
templatePath.copyToRecursively(module.sourcesDirectory, followLinks = false)
|
||||
return module
|
||||
}
|
||||
}
|
||||
|
||||
fun BaseCompilationTest.project(action: Project.() -> Unit) {
|
||||
Project(workingDirectory).action()
|
||||
}
|
||||
Reference in New Issue
Block a user