diff options
Diffstat (limited to 'atomicfu-gradle-plugin')
30 files changed, 1080 insertions, 583 deletions
diff --git a/atomicfu-gradle-plugin/build.gradle b/atomicfu-gradle-plugin/build.gradle index 28091b6..5312551 100644 --- a/atomicfu-gradle-plugin/build.gradle +++ b/atomicfu-gradle-plugin/build.gradle @@ -14,26 +14,41 @@ if (rootProject.ext.jvm_ir_enabled) { // Gradle plugin must be compiled targeting the same Kotlin version as used by Gradle kotlin.sourceSets.all { languageSettings { - apiVersion = "1.3" - languageVersion = "1.3" + apiVersion = "1.4" + languageVersion = "1.4" } } dependencies { - compile gradleApi() - compile project(":atomicfu-transformer") - compile 'org.jetbrains.kotlin:kotlin-stdlib' + implementation(project(":atomicfu-transformer")) { + exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib' + } + compileOnly gradleApi() + compileOnly 'org.jetbrains.kotlin:kotlin-stdlib' compileOnly "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + // atomicfu compiler plugin dependency will be loaded to kotlinCompilerPluginClasspath + implementation "org.jetbrains.kotlin:atomicfu:$kotlin_version" - testCompile gradleTestKit() - testCompile 'org.jetbrains.kotlin:kotlin-test' - testCompile 'org.jetbrains.kotlin:kotlin-test-junit' - testCompile 'junit:junit:4.12' + testImplementation gradleTestKit() + testImplementation 'org.jetbrains.kotlin:kotlin-test' + testImplementation 'org.jetbrains.kotlin:kotlin-test-junit' + testImplementation 'junit:junit:4.12' } configurations { - testPluginClasspath + testPluginClasspath { + attributes { + attribute( + Usage.USAGE_ATTRIBUTE, + project.objects.named(Usage.class, Usage.JAVA_RUNTIME) + ) + attribute( + Category.CATEGORY_ATTRIBUTE, + project.objects.named(Category.class, Category.LIBRARY) + ) + } + } } dependencies { diff --git a/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt b/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt index bb619a5..b77e95b 100644 --- a/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt +++ b/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt @@ -14,22 +14,33 @@ import org.gradle.api.tasks.compile.* import org.gradle.api.tasks.testing.* import org.gradle.jvm.tasks.* import org.jetbrains.kotlin.gradle.dsl.* +import org.jetbrains.kotlin.gradle.dsl.KotlinCompile import org.jetbrains.kotlin.gradle.plugin.* import java.io.* import java.util.* import java.util.concurrent.* +import org.jetbrains.kotlin.gradle.targets.js.* +import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget +import org.jetbrains.kotlin.gradle.tasks.* +import org.jetbrains.kotlinx.atomicfu.gradle.* private const val EXTENSION_NAME = "atomicfu" private const val ORIGINAL_DIR_NAME = "originalClassesDir" private const val COMPILE_ONLY_CONFIGURATION = "compileOnly" private const val IMPLEMENTATION_CONFIGURATION = "implementation" private const val TEST_IMPLEMENTATION_CONFIGURATION = "testImplementation" +// If the project uses KGP <= 1.6.20, only JS IR compiler plugin is available, and it is turned on via setting this property. +// The property is supported for backwards compatibility. +private const val ENABLE_JS_IR_TRANSFORMATION_LEGACY = "kotlinx.atomicfu.enableIrTransformation" +private const val ENABLE_JS_IR_TRANSFORMATION = "kotlinx.atomicfu.enableJsIrTransformation" +private const val ENABLE_JVM_IR_TRANSFORMATION = "kotlinx.atomicfu.enableJvmIrTransformation" open class AtomicFUGradlePlugin : Plugin<Project> { override fun apply(project: Project) = project.run { val pluginVersion = rootProject.buildscript.configurations.findByName("classpath") ?.allDependencies?.find { it.name == "atomicfu-gradle-plugin" }?.version extensions.add(EXTENSION_NAME, AtomicFUPluginExtension(pluginVersion)) + applyAtomicfuCompilerPlugin() configureDependencies() configureTasks() } @@ -43,12 +54,13 @@ private fun Project.configureDependencies() { ) dependencies.add(TEST_IMPLEMENTATION_CONFIGURATION, getAtomicfuDependencyNotation(Platform.JVM, version)) } - withPluginWhenEvaluatedDependencies("kotlin2js") { version -> + withPluginWhenEvaluatedDependencies("org.jetbrains.kotlin.js") { version -> dependencies.add( if (config.transformJs) COMPILE_ONLY_CONFIGURATION else IMPLEMENTATION_CONFIGURATION, getAtomicfuDependencyNotation(Platform.JS, version) ) dependencies.add(TEST_IMPLEMENTATION_CONFIGURATION, getAtomicfuDependencyNotation(Platform.JS, version)) + addCompilerPluginDependency() } withPluginWhenEvaluatedDependencies("kotlin-multiplatform") { version -> configureMultiplatformPluginDependencies(version) @@ -59,7 +71,9 @@ private fun Project.configureTasks() { val config = config withPluginWhenEvaluated("kotlin") { if (config.transformJvm) { - configureTransformTasks("compileTestKotlin") { sourceSet, transformedDir, originalDir -> + // skip transformation task if ir transformation is enabled + if (rootProject.getBooleanProperty(ENABLE_JVM_IR_TRANSFORMATION)) return@withPluginWhenEvaluated + configureJvmTransformation("compileTestKotlin") { sourceSet, transformedDir, originalDir -> createJvmTransformTask(sourceSet).configureJvmTask( sourceSet.compileClasspath, sourceSet.classesTaskName, @@ -70,20 +84,88 @@ private fun Project.configureTasks() { } } } - withPluginWhenEvaluated("kotlin2js") { - if (config.transformJs) { - configureTransformTasks("compileTestKotlin2Js") { sourceSet, transformedDir, originalDir -> - createJsTransformTask(sourceSet).configureJsTask( - sourceSet.classesTaskName, - transformedDir, - originalDir, - config - ) + withPluginWhenEvaluated("org.jetbrains.kotlin.js") { + if (config.transformJs) configureJsTransformation() + } + withPluginWhenEvaluated("kotlin-multiplatform") { + configureMultiplatformTransformation() + } +} + +private data class KotlinVersion(val major: Int, val minor: Int, val patch: Int) + +private fun Project.getKotlinVersion(): KotlinVersion { + val kotlinVersion = getKotlinPluginVersion() + val (major, minor) = kotlinVersion + .split('.') + .take(2) + .map { it.toInt() } + val patch = kotlinVersion.substringAfterLast('.').substringBefore('-').toInt() + return KotlinVersion(major, minor, patch) +} + +private fun KotlinVersion.atLeast(major: Int, minor: Int, patch: Int) = + this.major == major && (this.minor == minor && this.patch >= patch || this.minor > minor) || this.major > major + +// kotlinx-atomicfu compiler plugin is available for KGP >= 1.6.20 +private fun Project.isCompilerPluginAvailable() = getKotlinVersion().atLeast(1, 6, 20) + +private fun Project.applyAtomicfuCompilerPlugin() { + val kotlinVersion = getKotlinVersion() + // for KGP >= 1.7.20: + // compiler plugin for JS IR is applied via the property `kotlinx.atomicfu.enableJsIrTransformation` + // compiler plugin for JVM IR is applied via the property `kotlinx.atomicfu.enableJvmIrTransformation` + if (kotlinVersion.atLeast(1, 7, 20)) { + plugins.apply(AtomicfuKotlinGradleSubplugin::class.java) + extensions.getByType(AtomicfuKotlinGradleSubplugin.AtomicfuKotlinGradleExtension::class.java).apply { + isJsIrTransformationEnabled = rootProject.getBooleanProperty(ENABLE_JS_IR_TRANSFORMATION) + isJvmIrTransformationEnabled = rootProject.getBooleanProperty(ENABLE_JVM_IR_TRANSFORMATION) + } + } else { + // for KGP >= 1.6.20 && KGP <= 1.7.20: + // compiler plugin for JS IR is applied via the property `kotlinx.atomicfu.enableIrTransformation` + // compiler plugin for JVM IR is not supported yet + if (kotlinVersion.atLeast(1, 6, 20)) { + if (rootProject.getBooleanProperty(ENABLE_JS_IR_TRANSFORMATION_LEGACY)) { + plugins.apply(AtomicfuKotlinGradleSubplugin::class.java) } } } - withPluginWhenEvaluated("kotlin-multiplatform") { - configureMultiplatformPluginTasks() +} + +private fun Project.getBooleanProperty(name: String) = + rootProject.findProperty(name)?.toString()?.toBooleanStrict() ?: false + +private fun String.toBooleanStrict(): Boolean = when (this) { + "true" -> true + "false" -> false + else -> throw IllegalArgumentException("The string doesn't represent a boolean value: $this") +} + +private fun Project.needsJsIrTransformation(target: KotlinTarget): Boolean = + (rootProject.getBooleanProperty(ENABLE_JS_IR_TRANSFORMATION) || rootProject.getBooleanProperty(ENABLE_JS_IR_TRANSFORMATION_LEGACY)) + && target.isJsIrTarget() + +private fun KotlinTarget.isJsIrTarget() = (this is KotlinJsTarget && this.irTarget != null) || this is KotlinJsIrTarget + +private fun Project.addCompilerPluginDependency() { + if (isCompilerPluginAvailable()) { + withKotlinTargets { target -> + if (needsJsIrTransformation(target)) { + target.compilations.forEach { kotlinCompilation -> + kotlinCompilation.dependencies { + if (getKotlinVersion().atLeast(1, 7, 10)) { + // since Kotlin 1.7.10 we can add `atomicfu-runtime` dependency directly + implementation("org.jetbrains.kotlin:kotlinx-atomicfu-runtime:${getKotlinPluginVersion()}") + } else { + // add atomicfu compiler plugin dependency + // to provide the `atomicfu-runtime` library used during compiler plugin transformation + implementation("org.jetbrains.kotlin:atomicfu:${getKotlinPluginVersion()}") + } + } + } + } + } } } @@ -135,88 +217,112 @@ fun Project.withPluginWhenEvaluatedDependencies(plugin: String, fn: Project.(ver } fun Project.withKotlinTargets(fn: (KotlinTarget) -> Unit) { - extensions.findByType(KotlinProjectExtension::class.java)?.let { kotlinExtension -> - val targetsExtension = (kotlinExtension as? ExtensionAware)?.extensions?.findByName("targets") - @Suppress("UNCHECKED_CAST") - val targets = targetsExtension as NamedDomainObjectContainer<KotlinTarget> + extensions.findByType(KotlinTargetsContainer::class.java)?.let { kotlinExtension -> // find all compilations given sourceSet belongs to - targets.all { target -> fn(target) } + kotlinExtension.targets + .all { target -> fn(target) } } } -private fun KotlinCommonOptions.addFriendPaths(friendPathsFileCollection: FileCollection) { - val argName = when (this) { - is KotlinJvmOptions -> "-Xfriend-paths" - is KotlinJsOptions -> "-Xfriend-modules" - else -> return +private fun KotlinCompile<*>.setFriendPaths(friendPathsFileCollection: FileCollection) { + val (majorVersion, minorVersion) = project.getKotlinPluginVersion() + .split('.') + .take(2) + .map { it.toInt() } + if (majorVersion == 1 && minorVersion < 7) { + (this as? AbstractKotlinCompile<*>)?.friendPaths?.from(friendPathsFileCollection) + } else { + // See KT-KT-54167 (works only for KGP 1.7.0+) + (this as BaseKotlinCompile).friendPaths.from(friendPathsFileCollection) } - freeCompilerArgs = freeCompilerArgs + "$argName=${friendPathsFileCollection.joinToString(",")}" } -fun Project.configureMultiplatformPluginTasks() { - val originalDirsByCompilation = hashMapOf<KotlinCompilation<*>, FileCollection>() - val config = config +fun Project.configureJsTransformation() = + configureTransformationForTarget((kotlinExtension as KotlinJsProjectExtension).js()) + +fun Project.configureMultiplatformTransformation() = withKotlinTargets { target -> if (target.platformType == KotlinPlatformType.common || target.platformType == KotlinPlatformType.native) { return@withKotlinTargets // skip the common & native targets -- no transformation for them } - target.compilations.all compilations@{ compilation -> - val compilationType = compilation.name.compilationNameToType() - ?: return@compilations // skip unknown compilations - val classesDirs = compilation.output.classesDirs - // make copy of original classes directory - val originalClassesDirs: FileCollection = - project.files(classesDirs.from.toTypedArray()).filter { it.exists() } - originalDirsByCompilation[compilation] = originalClassesDirs - val transformedClassesDir = - project.buildDir.resolve("classes/atomicfu/${target.name}/${compilation.name}") - val transformTask = when (target.platformType) { - KotlinPlatformType.jvm, KotlinPlatformType.androidJvm -> { - if (!config.transformJvm) return@compilations // skip when transformation is turned off - project.createJvmTransformTask(compilation).configureJvmTask( - compilation.compileDependencyFiles, - compilation.compileAllTaskName, - transformedClassesDir, - originalClassesDirs, - config - ) - } - KotlinPlatformType.js -> { - if (!config.transformJs) return@compilations // skip when transformation is turned off - project.createJsTransformTask(compilation).configureJsTask( - compilation.compileAllTaskName, - transformedClassesDir, - originalClassesDirs, - config - ) - } - else -> error("Unsupported transformation platform '${target.platformType}'") - } - //now transformTask is responsible for compiling this source set into the classes directory - classesDirs.setFrom(transformedClassesDir) - classesDirs.builtBy(transformTask) - (tasks.findByName(target.artifactsTaskName) as? Jar)?.apply { - setupJarManifest(multiRelease = config.variant.toVariant() == Variant.BOTH) + configureTransformationForTarget(target) + } + +private fun Project.configureTransformationForTarget(target: KotlinTarget) { + val originalDirsByCompilation = hashMapOf<KotlinCompilation<*>, FileCollection>() + val config = config + target.compilations.all compilations@{ compilation -> + val compilationType = compilation.name.compilationNameToType() + ?: return@compilations // skip unknown compilations + val classesDirs = compilation.output.classesDirs + // make copy of original classes directory + val originalClassesDirs: FileCollection = + project.files(classesDirs.from.toTypedArray()).filter { it.exists() } + originalDirsByCompilation[compilation] = originalClassesDirs + val transformedClassesDir = + project.buildDir.resolve("classes/atomicfu/${target.name}/${compilation.name}") + val transformTask = when (target.platformType) { + KotlinPlatformType.jvm, KotlinPlatformType.androidJvm -> { + // skip transformation task if transformation is turned off or ir transformation is enabled + if (!config.transformJvm || rootProject.getBooleanProperty(ENABLE_JVM_IR_TRANSFORMATION)) return@compilations + project.createJvmTransformTask(compilation).configureJvmTask( + compilation.compileDependencyFiles, + compilation.compileAllTaskName, + transformedClassesDir, + originalClassesDirs, + config + ) } - // test should compile and run against original production binaries - if (compilationType == CompilationType.TEST) { - val mainCompilation = - compilation.target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME) - val originalMainClassesDirs = project.files( - // use Callable because there is no guarantee that main is configured before test - Callable { originalDirsByCompilation[mainCompilation]!! } + KotlinPlatformType.js -> { + // skip when js transformation is not needed or when IR is transformed + if (!config.transformJs || (needsJsIrTransformation(target))) { + return@compilations + } + project.createJsTransformTask(compilation).configureJsTask( + compilation.compileAllTaskName, + transformedClassesDir, + originalClassesDirs, + config ) + } + else -> error("Unsupported transformation platform '${target.platformType}'") + } + //now transformTask is responsible for compiling this source set into the classes directory + classesDirs.setFrom(transformedClassesDir) + classesDirs.builtBy(transformTask) + (tasks.findByName(target.artifactsTaskName) as? Jar)?.apply { + setupJarManifest(multiRelease = config.jvmVariant.toJvmVariant() == JvmVariant.BOTH) + } + // test should compile and run against original production binaries + if (compilationType == CompilationType.TEST) { + val mainCompilation = + compilation.target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME) + val originalMainClassesDirs = project.files( + // use Callable because there is no guarantee that main is configured before test + Callable { originalDirsByCompilation[mainCompilation]!! } + ) + // KGP >= 1.7.0 has breaking changes in task hierarchy: + // https://youtrack.jetbrains.com/issue/KT-32805#focus=Comments-27-5915479.0-0 + val (majorVersion, minorVersion) = getKotlinPluginVersion() + .split('.') + .take(2) + .map { it.toInt() } + if (majorVersion == 1 && minorVersion < 7) { (tasks.findByName(compilation.compileKotlinTaskName) as? AbstractCompile)?.classpath = originalMainClassesDirs + compilation.compileDependencyFiles - mainCompilation.output.classesDirs + } else { + (tasks.findByName(compilation.compileKotlinTaskName) as? AbstractKotlinCompileTool<*>) + ?.libraries + ?.setFrom( + originalMainClassesDirs + compilation.compileDependencyFiles - mainCompilation.output.classesDirs + ) + } - (tasks.findByName("${target.name}${compilation.name.capitalize()}") as? Test)?.classpath = - originalMainClassesDirs + (compilation as KotlinCompilationToRunnableFiles).runtimeDependencyFiles - mainCompilation.output.classesDirs + (tasks.findByName("${target.name}${compilation.name.capitalize()}") as? Test)?.classpath = + originalMainClassesDirs + (compilation as KotlinCompilationToRunnableFiles).runtimeDependencyFiles - mainCompilation.output.classesDirs - compilation.compileKotlinTask.doFirst { - compilation.kotlinOptions.addFriendPaths(originalMainClassesDirs) - } - } + compilation.compileKotlinTask.setFriendPaths(originalMainClassesDirs) } } } @@ -234,15 +340,16 @@ fun Project.sourceSetsByCompilation(): Map<KotlinSourceSet, List<KotlinCompilati } fun Project.configureMultiplatformPluginDependencies(version: String) { - if (rootProject.findProperty("kotlin.mpp.enableGranularSourceSetsMetadata").toString().toBoolean()) { + if (rootProject.getBooleanProperty("kotlin.mpp.enableGranularSourceSetsMetadata")) { + addCompilerPluginDependency() val mainConfigurationName = project.extensions.getByType(KotlinMultiplatformExtension::class.java).sourceSets - .getByName(KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME) - .compileOnlyConfigurationName + .getByName(KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME) + .compileOnlyConfigurationName dependencies.add(mainConfigurationName, getAtomicfuDependencyNotation(Platform.MULTIPLATFORM, version)) val testConfigurationName = project.extensions.getByType(KotlinMultiplatformExtension::class.java).sourceSets - .getByName(KotlinSourceSet.COMMON_TEST_SOURCE_SET_NAME) - .implementationConfigurationName + .getByName(KotlinSourceSet.COMMON_TEST_SOURCE_SET_NAME) + .implementationConfigurationName dependencies.add(testConfigurationName, getAtomicfuDependencyNotation(Platform.MULTIPLATFORM, version)) // For each source set that is only used in Native compilations, add an implementation dependency so that it @@ -258,20 +365,21 @@ fun Project.configureMultiplatformPluginDependencies(version: String) { } } else { sourceSetsByCompilation().forEach { (sourceSet, compilations) -> + addCompilerPluginDependency() val platformTypes = compilations.map { it.platformType }.toSet() val compilationNames = compilations.map { it.compilationName }.toSet() if (compilationNames.size != 1) error("Source set '${sourceSet.name}' of project '$name' is part of several compilations $compilationNames") val compilationType = compilationNames.single().compilationNameToType() - ?: return@forEach // skip unknown compilations + ?: return@forEach // skip unknown compilations val platform = - if (platformTypes.size > 1) Platform.MULTIPLATFORM else // mix of platform types -> "common" - when (platformTypes.single()) { - KotlinPlatformType.common -> Platform.MULTIPLATFORM - KotlinPlatformType.jvm, KotlinPlatformType.androidJvm -> Platform.JVM - KotlinPlatformType.js -> Platform.JS - KotlinPlatformType.native -> Platform.NATIVE - } + if (platformTypes.size > 1) Platform.MULTIPLATFORM else // mix of platform types -> "common" + when (platformTypes.single()) { + KotlinPlatformType.common -> Platform.MULTIPLATFORM + KotlinPlatformType.jvm, KotlinPlatformType.androidJvm -> Platform.JVM + KotlinPlatformType.js -> Platform.JS + KotlinPlatformType.native, KotlinPlatformType.wasm -> Platform.NATIVE + } val configurationName = when { // impl dependency for native (there is no transformation) platform == Platform.NATIVE -> sourceSet.implementationConfigurationName @@ -285,7 +393,7 @@ fun Project.configureMultiplatformPluginDependencies(version: String) { } } -fun Project.configureTransformTasks( +fun Project.configureJvmTransformation( testTaskName: String, createTransformTask: (sourceSet: SourceSet, transformedDir: File, originalDir: FileCollection) -> Task ) { @@ -305,7 +413,7 @@ fun Project.configureTransformTasks( //now transformTask is responsible for compiling this source set into the classes directory sourceSet.compiledBy(transformTask) (tasks.findByName(sourceSet.jarTaskName) as? Jar)?.apply { - setupJarManifest(multiRelease = config.variant.toVariant() == Variant.BOTH) + setupJarManifest(multiRelease = config.jvmVariant.toJvmVariant() == JvmVariant.BOTH) } // test should compile and run against original production binaries if (compilationType == CompilationType.TEST) { @@ -319,9 +427,7 @@ fun Project.configureTransformTasks( classpath = originalMainClassesDirs + sourceSet.compileClasspath - mainSourceSet.output.classesDirs - (this as? KotlinCompile<*>)?.doFirst { - kotlinOptions.addFriendPaths(originalMainClassesDirs) - } + (this as? KotlinCompile<*>)?.setFriendPaths(originalMainClassesDirs) } // todo: fix test runtime classpath for JS? @@ -331,7 +437,7 @@ fun Project.configureTransformTasks( } } -fun String.toVariant(): Variant = enumValueOf(toUpperCase(Locale.US)) +fun String.toJvmVariant(): JvmVariant = enumValueOf(toUpperCase(Locale.US)) fun Project.createJvmTransformTask(compilation: KotlinCompilation<*>): AtomicFUTransformTask = tasks.create( @@ -348,9 +454,6 @@ fun Project.createJsTransformTask(compilation: KotlinCompilation<*>): AtomicFUTr fun Project.createJvmTransformTask(sourceSet: SourceSet): AtomicFUTransformTask = tasks.create(sourceSet.getTaskName("transform", "atomicfuClasses"), AtomicFUTransformTask::class.java) -fun Project.createJsTransformTask(sourceSet: SourceSet): AtomicFUTransformJsTask = - tasks.create(sourceSet.getTaskName("transform", "atomicfuJsFiles"), AtomicFUTransformJsTask::class.java) - fun AtomicFUTransformTask.configureJvmTask( classpath: FileCollection, classesTaskName: String, @@ -363,7 +466,7 @@ fun AtomicFUTransformTask.configureJvmTask( classPath = classpath inputFiles = originalClassesDir outputDir = transformedClassesDir - variant = config.variant + jvmVariant = config.jvmVariant verbose = config.verbose } @@ -395,7 +498,7 @@ class AtomicFUPluginExtension(pluginVersion: String?) { var dependenciesVersion = pluginVersion var transformJvm = true var transformJs = true - var variant: String = "FU" + var jvmVariant: String = "FU" var verbose: Boolean = false } @@ -413,7 +516,8 @@ open class AtomicFUTransformTask : ConventionTask() { lateinit var classPath: FileCollection @Input - var variant = "FU" + var jvmVariant = "FU" + @Input var verbose = false @@ -422,7 +526,7 @@ open class AtomicFUTransformTask : ConventionTask() { val cp = classPath.files.map { it.absolutePath } inputFiles.files.forEach { inputDir -> AtomicFUTransformer(cp, inputDir, outputDir).let { t -> - t.variant = variant.toVariant() + t.jvmVariant = jvmVariant.toJvmVariant() t.verbose = verbose t.transform() } @@ -438,6 +542,7 @@ open class AtomicFUTransformJsTask : ConventionTask() { @OutputDirectory lateinit var outputDir: File + @Input var verbose = false diff --git a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/BaseKotlinGradleTest.kt b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/BaseKotlinGradleTest.kt deleted file mode 100644 index b81a0c9..0000000 --- a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/BaseKotlinGradleTest.kt +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2017-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package kotlinx.atomicfu.plugin.gradle - -import org.gradle.internal.impldep.com.google.common.io.Files -import org.junit.After -import org.junit.Before -import java.io.File - -abstract class BaseKotlinGradleTest { - private lateinit var workingDir: File - - fun project(name: String, suffix: String = "", fn: Project.() -> Unit) { - workingDir = File("build${File.separator}test-$name$suffix").absoluteFile - workingDir.deleteRecursively() - workingDir.mkdirs() - val testResources = File("src/test/resources") - val originalProjectDir = testResources.resolve("projects/$name").apply { checkExists() } - val projectDir = workingDir.resolve(name).apply { mkdirs() } - originalProjectDir.listFiles().forEach { it.copyRecursively(projectDir.resolve(it.name)) } - - // Add an empty setting.gradle - projectDir.resolve("settings.gradle").writeText("// this file is intentionally left empty") - - Project(projectDir = projectDir).fn() - } -}
\ No newline at end of file diff --git a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/EmptyProjectTest.kt b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/EmptyProjectTest.kt deleted file mode 100644 index b542f2b..0000000 --- a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/EmptyProjectTest.kt +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright 2017-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package kotlinx.atomicfu.plugin.gradle - -import org.junit.Test - -class EmptyProjectTest : BaseKotlinGradleTest() { - @Test - fun testEmpty() = project("empty") { - build("build") {} - } -} diff --git a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/JsProjectTest.kt b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/JsProjectTest.kt deleted file mode 100644 index 2201199..0000000 --- a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/JsProjectTest.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2017-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package kotlinx.atomicfu.plugin.gradle - -import org.gradle.testkit.runner.TaskOutcome -import org.junit.Test -import java.io.File - -class JsProjectTest : BaseKotlinGradleTest() { - @Test - fun testKotlin2JsPlugin() = project("js-simple") { - val tasksToCheck = arrayOf( - ":compileKotlin2Js", - ":compileTestKotlin2Js", - ":transformAtomicfuJsFiles", - ":transformTestAtomicfuJsFiles" - ) - - build("build") { - checkOutcomes(TaskOutcome.SUCCESS, *tasksToCheck) - - val testCompileClasspathFiles = projectDir.resolve("build/test_compile_classpath.txt") - .readLines().asSequence().flatMap { File(it).walk().filter(File::isFile) }.toHashSet() - - projectDir.resolve("build/classes/kotlin/main/js-simple.js").let { - it.checkExists() - check(it in testCompileClasspathFiles) { "Original '$it' is missing from test compile classpath" } - // todo: check test runtime classpath when js test tasks are supported in plugin - } - - projectDir.resolve("build/classes/atomicfu/main/js-simple.js").let { - it.checkExists() - check(it !in testCompileClasspathFiles) { "Transformed '$it' is present in test compile classpath" } - } - } - - build("build") { - checkOutcomes(TaskOutcome.UP_TO_DATE, *tasksToCheck) - } - } -} diff --git a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/JvmProjectTest.kt b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/JvmProjectTest.kt deleted file mode 100644 index e017f05..0000000 --- a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/JvmProjectTest.kt +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2017-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package kotlinx.atomicfu.plugin.gradle - -import org.gradle.testkit.runner.TaskOutcome -import org.junit.Test -import java.io.File - -class JvmProjectTest : BaseKotlinGradleTest() { - @Test - fun testKotlinPlugin() = - project("jvm-simple") { - doSimpleTest() - } - - @Test - fun testKotlinPlatformJvmPlugin() = - project("jvm-simple", "-platform") { - projectDir.resolve("build.gradle").modify { - it.checkedReplace("apply plugin: 'kotlin'", "apply plugin: 'kotlin-platform-jvm'") - } - doSimpleTest() - } - - private fun Project.doSimpleTest() { - val tasksToCheck = arrayOf( - ":compileKotlin", - ":compileTestKotlin", - ":transformAtomicfuClasses", - ":transformTestAtomicfuClasses" - ) - - build("build") { - checkOutcomes(TaskOutcome.SUCCESS, *tasksToCheck) - - val testCompileClasspathFiles = filesFrom("build/test_compile_classpath.txt") - val testRuntimeClasspathFiles = filesFrom("build/test_runtime_classpath.txt") - - projectDir.resolve("build/classes/kotlin/main/IntArithmetic.class").let { - it.checkExists() - check(it in testCompileClasspathFiles) { "Original '$it' is missing from test compile classpath" } - check(it in testRuntimeClasspathFiles) { "Original '$it' is missing from test runtime classpath" } - } - - projectDir.resolve("build/classes/atomicfu/main/IntArithmetic.class").let { - it.checkExists() - check(it !in testCompileClasspathFiles) { "Transformed '$it' is present in test compile classpath" } - check(it !in testRuntimeClasspathFiles) { "Transformed '$it' is present in test runtime classpath" } - } - } - - build("build") { - checkOutcomes(TaskOutcome.UP_TO_DATE, *tasksToCheck) - } - } - - private fun Project.filesFrom(name: String) = projectDir.resolve(name) - .readLines().asSequence().flatMap { listFiles(it) }.toHashSet() - - private fun listFiles(dir: String): Sequence<File> = File(dir).walk().filter { it.isFile } -} diff --git a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/MppProjectTest.kt b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/MppProjectTest.kt deleted file mode 100644 index 6dd7fa1..0000000 --- a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/MppProjectTest.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2017-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package kotlinx.atomicfu.plugin.gradle - -import org.gradle.testkit.runner.TaskOutcome -import org.junit.Test -import java.io.File - -class MppProjectTest : BaseKotlinGradleTest() { - @Test - fun testKotlinMultiplatformPlugin() = project("mpp-simple") { - val tasksToCheck = arrayOf( - ":compileKotlinJvm", - ":compileTestKotlinJvm", - ":transformJvmMainAtomicfu", - ":transformJvmTestAtomicfu", - ":compileKotlinJs", - ":transformJsMainAtomicfu" - ) - - build("build") { - checkOutcomes(TaskOutcome.SUCCESS, *tasksToCheck) - - fun checkPlatform(platform: String, fileInMainName: String) { - val isJs = platform == "js" - val testCompileClasspathFiles = projectDir.resolve("build/classpath/$platform/test_compile.txt") - .readLines().asSequence().flatMapTo(HashSet()) { File(it).walk().filter(File::isFile) } - val testRuntimeClasspathFiles = if (isJs) emptySet<File>() else projectDir.resolve("build/classpath/$platform/test_runtime.txt") - .readLines().asSequence().flatMapTo(HashSet()) { File(it).walk().filter(File::isFile) } - - projectDir.resolve("build/classes/kotlin/$platform/main/$fileInMainName").let { - it.checkExists() - check(it in testCompileClasspathFiles) { "Original '$it' is missing from $platform test compile classpath" } - if (!isJs) check(it in testRuntimeClasspathFiles) { "Original '$it' is missing from $platform test runtime classpath" } - } - - projectDir.resolve("build/classes/atomicfu/jvm/main/IntArithmetic.class").let { - it.checkExists() - check(it !in testCompileClasspathFiles) { "Transformed '$it' is present in $platform test compile classpath" } - if (!isJs) check(it !in testRuntimeClasspathFiles) { "Transformed '$it' is present in $platform test runtime classpath" } - } - - } - - checkPlatform("jvm", "IntArithmetic.class") - checkPlatform("js", "mpp-simple.js") - } - - build("build") { - checkOutcomes(TaskOutcome.UP_TO_DATE, *tasksToCheck) - } - } -} diff --git a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/Project.kt b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/Project.kt deleted file mode 100644 index f3f49e1..0000000 --- a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/Project.kt +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2017-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package kotlinx.atomicfu.plugin.gradle - -import org.gradle.testkit.runner.BuildResult -import org.gradle.testkit.runner.GradleRunner -import java.io.File - -class Project(val projectDir: File) { - init { - projectDir.resolve("build.gradle").modify { - buildScript + "\n\n" + it - } - } - - private var isDebug = false - private var printStdout = false - - @Deprecated("Should be used for debug only!") - @Suppress("unused") - fun debug() { - isDebug = true - } - - /** - * Redirects Gradle runner output to stdout. Useful for debugging. - */ - @Deprecated("Should be used for debug only!") - @Suppress("unused") - fun printStdout() { - printStdout = true - } - - fun gradle(vararg tasks: String): GradleRunner = - GradleRunner.create() - .withDebug(isDebug) - .withProjectDir(projectDir) - .withArguments(*(defaultArguments() + tasks)) - .run { - if (printStdout) { - forwardStdOutput(System.out.bufferedWriter()) - } else { - this - } - } - - fun build(vararg tasks: String, fn: BuildResult.() -> Unit = {}) { - val gradle = gradle(*tasks) - val buildResult = gradle.build() - buildResult.fn() - } - - @Suppress("unused") - fun buildAndFail(vararg tasks: String, fn: BuildResult.() -> Unit = {}) { - val gradle = gradle(*tasks) - val buildResult = gradle.buildAndFail() - buildResult.fn() - } - - private fun defaultArguments(): Array<String> = - arrayOf("--stacktrace") - - companion object { - private fun readFileList(fileName: String): String { - val resource = Project::class.java.classLoader.getResource(fileName) - ?: throw IllegalStateException("Could not find resource '$fileName'") - val files = File(resource.toURI()) - .readLines() - .map { File(it).absolutePath.replace("\\", "\\\\") } // escape backslashes in Windows paths - return files.joinToString(", ") { "'$it'" } - } - - private val buildScript = run { - """ - buildscript { - dependencies { - classpath files(${readFileList("plugin-classpath.txt")}) - } - } - - repositories { - jcenter() - mavenCentral() - maven { url 'https://cache-redirector.jetbrains.com/maven.pkg.jetbrains.space/kotlin/p/kotlin/dev' } - maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' } - maven { url 'https://dl.bintray.com/kotlin/kotlin-dev' } - maven { url 'https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev' } - maven { url "https://oss.sonatype.org/content/repositories/snapshots" } - } - - def atomicfuJvm = files(${readFileList("atomicfu-jvm.txt")}) - def atomicfuJs = files(${readFileList("atomicfu-js.txt")}) - def atomicfuMetadata = files(${readFileList("atomicfu-metadata.txt")}) - """.trimIndent() - } - } -} diff --git a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/internal/Assert.kt b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/internal/Assert.kt new file mode 100644 index 0000000..f55e38a --- /dev/null +++ b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/internal/Assert.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2016-2022 JetBrains s.r.o. + * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. + */ + +package kotlinx.atomicfu.plugin.gradle.internal + +import org.gradle.testkit.runner.BuildResult +import org.gradle.testkit.runner.TaskOutcome +import kotlin.test.assertEquals + +/** + * Helper `fun` for asserting a [TaskOutcome] to be equal to [TaskOutcome.SUCCESS] + */ +internal fun BuildResult.assertTaskSuccess(task: String) { + assertTaskOutcome(TaskOutcome.SUCCESS, task) +} + +/** + * Helper `fun` for asserting a [TaskOutcome] to be equal to [TaskOutcome.FAILED] + */ +internal fun BuildResult.assertTaskFailure(task: String) { + assertTaskOutcome(TaskOutcome.FAILED, task) +} + +internal fun BuildResult.assertTaskUpToDate(task: String) { + assertTaskOutcome(TaskOutcome.UP_TO_DATE, task) +} + +private fun BuildResult.assertTaskOutcome(taskOutcome: TaskOutcome, taskName: String) { + assertEquals(taskOutcome, task(taskName)?.outcome) +} diff --git a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/internal/TestDsl.kt b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/internal/TestDsl.kt new file mode 100644 index 0000000..2541b41 --- /dev/null +++ b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/internal/TestDsl.kt @@ -0,0 +1,139 @@ +/* + * Copyright 2016-2022 JetBrains s.r.o. + * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. + */ + +package kotlinx.atomicfu.plugin.gradle.internal + +import kotlinx.atomicfu.plugin.gradle.test.* +import org.gradle.testkit.runner.* +import java.io.* + +internal fun BaseKotlinGradleTest.test(fn: BaseKotlinScope.() -> Unit): GradleRunner { + val baseKotlinScope = BaseKotlinScope() + fn(baseKotlinScope) + + baseKotlinScope.files.forEach { scope -> + val fileWriteTo = rootProjectDir.resolve(scope.filePath) + .apply { + parentFile.mkdirs() + createNewFile() + } + + scope.files.forEach { + val fileContent = readFileList(it) + fileWriteTo.appendText(fileContent) + } + } + + return GradleRunner.create() + .withProjectDir(rootProjectDir) + .withArguments(baseKotlinScope.runner.arguments) + .withPluginClasspath() + .addPluginTestRuntimeClasspath() +} + +/** + * same as [file][FileContainer.file], but prepends "src/${sourceSet}/kotlin" before given `classFileName` + */ +internal fun FileContainer.kotlin(classFileName: String, sourceSet: String = "main", fn: AppendableScope.() -> Unit) { + require(classFileName.endsWith(".kt")) { + "ClassFileName must end with '.kt'" + } + + val fileName = "src/${sourceSet}/kotlin/$classFileName" + file(fileName, fn) +} + +/** + * Shortcut for creating a `build.gradle.kts` by using [file][FileContainer.file] + */ +internal fun FileContainer.buildGradleKts(fn: AppendableScope.() -> Unit) { + val fileName = "build.gradle.kts" + file(fileName, fn) +} + +/** + * Shortcut for creating a `settings.gradle.kts` by using [file][FileContainer.file] + */ +internal fun FileContainer.settingsGradleKts(fn: AppendableScope.() -> Unit) { + val fileName = "settings.gradle.kts" + file(fileName, fn) +} + +/** + * Shortcut for creating a `gradle.properties` by using [file][FileContainer.file] + */ +internal fun FileContainer.gradleProperties(fn: AppendableScope.() -> Unit) { + val fileName = "gradle.properties" + file(fileName, fn) +} + +/** + * Declares a directory with the given [dirName] inside the current container. + * All calls creating files within this scope will create the files nested in this directory. + * + * Note that it is valid to call this method multiple times at the same level with the same [dirName]. + * Files declared within 2 independent calls to [dir] will be added to the same directory. + */ +internal fun FileContainer.dir(dirName: String, fn: DirectoryScope.() -> Unit) { + DirectoryScope(dirName, this).fn() +} + +internal fun BaseKotlinScope.runner(fn: Runner.() -> Unit) { + val runner = Runner() + fn(runner) + + this.runner = runner +} + +internal fun AppendableScope.resolve(fileName: String) { + this.files.add(fileName) +} + +internal interface FileContainer { + fun file(fileName: String, fn: AppendableScope.() -> Unit) +} + +internal class BaseKotlinScope : FileContainer { + var files: MutableList<AppendableScope> = mutableListOf() + var runner: Runner = Runner() + + override fun file(fileName: String, fn: AppendableScope.() -> Unit) { + val appendableScope = AppendableScope(fileName) + fn(appendableScope) + files.add(appendableScope) + } +} + +internal class DirectoryScope( + val dirPath: String, + val parent: FileContainer +): FileContainer { + + override fun file(fileName: String, fn: AppendableScope.() -> Unit) { + parent.file("$dirPath/$fileName", fn) + } +} + +internal class AppendableScope(val filePath: String) { + val files: MutableList<String> = mutableListOf() +} + +internal class Runner { + val arguments: MutableList<String> = mutableListOf() +} + +internal fun readFileList(fileName: String): String = + getFile(fileName).readText() + +internal fun getFile(fileName: String): File { + val resource = BaseKotlinGradleTest::class.java.classLoader.getResource(fileName) + ?: throw IllegalStateException("Could not find resource '$fileName'") + return File(resource.toURI()) +} + +internal fun GradleRunner.addPluginTestRuntimeClasspath() = apply { + val pluginClasspath = getFile("plugin-classpath.txt").readLines().map { File(it) } + withPluginClasspath(pluginClasspath) +} diff --git a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/internal/utils.kt b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/internal/utils.kt new file mode 100644 index 0000000..49856f2 --- /dev/null +++ b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/internal/utils.kt @@ -0,0 +1,13 @@ +package kotlinx.atomicfu.plugin.gradle.internal + +import java.io.* +import kotlin.test.* + +fun File.checkExists() { + assertTrue(exists(), "File does not exist: $canonicalPath") +} + +fun File.filesFrom(relative: String) = resolve(relative) + .readLines().asSequence().flatMap { listFiles(it) }.toHashSet() + +fun listFiles(dir: String): Sequence<File> = File(dir).walk().filter { it.isFile }
\ No newline at end of file diff --git a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/BaseKotlinGradleTest.kt b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/BaseKotlinGradleTest.kt new file mode 100644 index 0000000..e9ff7bb --- /dev/null +++ b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/BaseKotlinGradleTest.kt @@ -0,0 +1,108 @@ +/* + * Copyright 2017-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.atomicfu.plugin.gradle.test + +import kotlinx.atomicfu.plugin.gradle.internal.* +import org.objectweb.asm.* +import java.io.File +import kotlin.test.* + +abstract class BaseKotlinGradleTest(private val projectName: String) { + internal val rootProjectDir: File + private val ATOMIC_FU_REF = "Lkotlinx/atomicfu/".toByteArray() + private val KOTLIN_METADATA_DESC = "Lkotlin/Metadata;" + + init { + rootProjectDir = File("build${File.separator}test-$projectName").absoluteFile + rootProjectDir.deleteRecursively() + rootProjectDir.mkdirs() + } + + internal abstract fun BaseKotlinScope.createProject() + + val runner = test { + createProject() + runner { + arguments.add(":build") + } + } + + fun checkTaskOutcomes(executedTasks: List<String>, excludedTasks: List<String>) { + runner.build().apply { + val tasks = tasks.map { it.path } + excludedTasks.forEach { + check(it !in tasks) { "Post-compilation transformation task $it was added in the compiler plugin mode" } + } + executedTasks.forEach { + assertTaskSuccess(it) + } + } + // check that task outcomes are cached for the second build + runner.build().apply { + executedTasks.forEach { + assertTaskUpToDate(it) + } + } + } + + fun checkJvmCompilationClasspath(originalClassFile: String, transformedClassFile: String) { + // check that test compile and runtime classpath does not contain original non-transformed classes + val testCompileClasspathFiles = rootProjectDir.filesFrom("build/test_compile_jvm_classpath.txt") + val testRuntimeClasspathFiles = rootProjectDir.filesFrom("build/test_runtime_jvm_classpath.txt") + + rootProjectDir.resolve(transformedClassFile).let { + it.checkExists() + check(it in testCompileClasspathFiles) { "Transformed '$it' is missing from test compile classpath" } + check(it in testRuntimeClasspathFiles) { "Transformed '$it' is missing from test runtime classpath" } + } + + rootProjectDir.resolve(originalClassFile).let { + it.checkExists() + check(it !in testCompileClasspathFiles) { "Original '$it' is present in test compile classpath" } + check(it !in testRuntimeClasspathFiles) { "Original '$it' is present in test runtime classpath" } + } + } + + fun checkJsCompilationClasspath() { + // check that test compilation depends on transformed main sources + val testCompileClasspathFiles = rootProjectDir.filesFrom("build/test_compile_js_classpath.txt") + + rootProjectDir.resolve("build/classes/atomicfu/js/main/$projectName.js").let { + it.checkExists() + check(it in testCompileClasspathFiles) { "Transformed '$it' is missing from test compile classpath" } + } + } + + fun checkBytecode(classFilePath: String) { + rootProjectDir.resolve(classFilePath).let { + it.checkExists() + assertFalse(it.readBytes().findAtomicfuRef(), "Found 'Lkotlinx/atomicfu/' reference in $it" ) + } + } + + private fun ByteArray.findAtomicfuRef(): Boolean { + val bytes = this.eraseMetadata() + loop@for (i in 0 until bytes.size - ATOMIC_FU_REF.size) { + for (j in 0 until ATOMIC_FU_REF.size) { + if (bytes[i + j] != ATOMIC_FU_REF[j]) continue@loop + } + return true + } + return false + } + + // The atomicfu compiler plugin does not remove atomic properties from metadata, + // so for now we check that there are no ATOMIC_FU_REF left in the class bytecode excluding metadata. + // This may be reverted after the fix in the compiler plugin transformer (See #254). + private fun ByteArray.eraseMetadata(): ByteArray { + val cw = ClassWriter(ClassWriter.COMPUTE_MAXS or ClassWriter.COMPUTE_FRAMES) + ClassReader(this).accept(object : ClassVisitor(Opcodes.ASM9, cw) { + override fun visitAnnotation(descriptor: String?, visible: Boolean): AnnotationVisitor? { + return if (descriptor == KOTLIN_METADATA_DESC) null else super.visitAnnotation(descriptor, visible) + } + }, ClassReader.SKIP_FRAMES) + return cw.toByteArray() + } +} diff --git a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/JsProjectTest.kt b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/JsProjectTest.kt new file mode 100644 index 0000000..0b34955 --- /dev/null +++ b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/JsProjectTest.kt @@ -0,0 +1,49 @@ +package kotlinx.atomicfu.plugin.gradle.test + +import kotlinx.atomicfu.plugin.gradle.internal.* +import kotlinx.atomicfu.plugin.gradle.internal.BaseKotlinScope +import org.junit.Test + +/** + * Test that ensures correctness of `atomicfu-gradle-plugin` application to the JS project: + * - post-compilation js transformation tasks are created + * (legacy transformation is tested here, compiler plugin is not applied). + * - original non-transformed classes are not left in compile/runtime classpath. + */ +class JsLegacyTransformationTest : BaseKotlinGradleTest("js-simple") { + + override fun BaseKotlinScope.createProject() { + buildGradleKts { + resolve("projects/js-simple/js-simple.gradle.kts") + } + settingsGradleKts { + resolve("projects/js-simple/settings.gradle.kts") + } + dir("src/main/kotlin") {} + kotlin("IntArithmetic.kt", "main") { + resolve("projects/js-simple/src/main/kotlin/IntArithmetic.kt") + } + dir("src/test/kotlin") {} + kotlin("ArithmeticTest.kt", "test") { + resolve("projects/js-simple/src/test/kotlin/ArithmeticTest.kt") + } + } + + @Test + fun testPluginApplication() = + checkTaskOutcomes( + executedTasks = listOf( + ":compileKotlinJs", + ":transformJsMainAtomicfu", + ":compileTestKotlinJs", + ":transformJsTestAtomicfu" + ), + excludedTasks = emptyList() + ) + + @Test + fun testClasspath() { + runner.build() + checkJsCompilationClasspath() + } +} diff --git a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/JvmProjectTest.kt b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/JvmProjectTest.kt new file mode 100644 index 0000000..2545e0e --- /dev/null +++ b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/JvmProjectTest.kt @@ -0,0 +1,108 @@ +package kotlinx.atomicfu.plugin.gradle.test + +import kotlinx.atomicfu.plugin.gradle.internal.* +import kotlinx.atomicfu.plugin.gradle.internal.BaseKotlinScope +import org.junit.Test + +/** + * Test that ensures correctness of `atomicfu-gradle-plugin` application to the JVM project: + * - post-compilation bytecode transformation tasks are created + * (legacy transformation is tested here, compiler plugin is not applied). + * - original non-transformed classes are not left in compile/runtime classpath. + * - no `kotlinx/atomicfu` references are left in the transformed bytecode. + */ +class JvmLegacyTransformationTest : BaseKotlinGradleTest("jvm-simple") { + + override fun BaseKotlinScope.createProject() { + buildGradleKts { + resolve("projects/jvm-simple/jvm-simple.gradle.kts") + } + settingsGradleKts { + resolve("projects/jvm-simple/settings.gradle.kts") + } + dir("src/main/kotlin") {} + kotlin("IntArithmetic.kt", "main") { + resolve("projects/jvm-simple/src/main/kotlin/IntArithmetic.kt") + } + dir("src/test/kotlin") {} + kotlin("ArithmeticTest.kt", "test") { + resolve("projects/jvm-simple/src/test/kotlin/ArithmeticTest.kt") + } + } + + @Test + fun testPluginApplication() = + checkTaskOutcomes( + executedTasks = listOf( + ":compileKotlin", + ":transformAtomicfuClasses", + ":compileTestKotlin", + ":transformTestAtomicfuClasses" + ), + excludedTasks = emptyList() + ) + + @Test + fun testClasspath() { + runner.build() + checkJvmCompilationClasspath( + originalClassFile = "build/classes/kotlin/main/IntArithmetic.class", + transformedClassFile = "build/classes/atomicfu/main/IntArithmetic.class" + ) + } + + @Test + fun testAtomicfuReferences() { + runner.build() + checkBytecode("build/classes/atomicfu/main/IntArithmetic.class") + } +} + +/** + * Test that ensures correctness of `atomicfu-gradle-plugin` application to the JVM project, + * - JVM IR compiler plugin transformation (kotlinx.atomicfu.enableJvmIrTransformation=true) + * - no post-compilation bytecode transforming tasks created + * - no `kotlinx/atomicfu` references are left in the resulting bytecode after IR transformation. + */ +class JvmIrTransformationTest : BaseKotlinGradleTest("jvm-simple") { + + override fun BaseKotlinScope.createProject() { + buildGradleKts { + resolve("projects/jvm-simple/jvm-simple.gradle.kts") + } + settingsGradleKts { + resolve("projects/jvm-simple/settings.gradle.kts") + } + // set kotlinx.atomicfu.enableJvmIrTransformation=true to apply compiler plugin + gradleProperties { + resolve("projects/jvm-simple/gradle.properties") + } + dir("src/main/kotlin") {} + kotlin("IntArithmetic.kt", "main") { + resolve("projects/jvm-simple/src/main/kotlin/IntArithmetic.kt") + } + dir("src/test/kotlin") {} + kotlin("ArithmeticTest.kt", "test") { + resolve("projects/jvm-simple/src/test/kotlin/ArithmeticTest.kt") + } + } + + @Test + fun testPluginApplication() = + checkTaskOutcomes( + executedTasks = listOf( + ":compileKotlin", + ":compileTestKotlin" + ), + excludedTasks = listOf( + ":transformAtomicfuClasses", + ":transformTestAtomicfuClasses" + ) + ) + + @Test + fun testAtomicfuReferences() { + runner.build() + checkBytecode("build/classes/kotlin/main/IntArithmetic.class") + } +} diff --git a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/MppProjectTest.kt b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/MppProjectTest.kt new file mode 100644 index 0000000..e95b091 --- /dev/null +++ b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/MppProjectTest.kt @@ -0,0 +1,219 @@ +package kotlinx.atomicfu.plugin.gradle.test + +import kotlinx.atomicfu.plugin.gradle.internal.* +import org.junit.* + +/** + * Test that ensures correctness of `atomicfu-gradle-plugin` application to the MPP project: + * - post-compilation bytecode transformation tasks are created + * (legacy transformation is tested here, compiler plugin is not applied). + * - original non-transformed classes are not left in compile/runtime classpath. + * - no `kotlinx/atomicfu` references are left in the transformed bytecode. + */ +class MppLegacyTransformationTest : BaseKotlinGradleTest("mpp-simple") { + + override fun BaseKotlinScope.createProject() { + buildGradleKts { + resolve("projects/mpp-simple/mpp-simple.gradle.kts") + } + settingsGradleKts { + resolve("projects/mpp-simple/settings.gradle.kts") + } + dir("src/commonMain/kotlin") {} + kotlin("IntArithmetic.kt", "commonMain") { + resolve("projects/mpp-simple/src/commonMain/kotlin/IntArithmetic.kt") + } + dir("src/commonTest/kotlin") {} + kotlin("ArithmeticTest.kt", "commonTest") { + resolve("projects/mpp-simple/src/commonTest/kotlin/ArithmeticTest.kt") + } + } + + @Test + fun testPluginApplication() = + checkTaskOutcomes( + executedTasks = listOf( + ":compileKotlinJvm", + ":compileTestKotlinJvm", + ":transformJvmMainAtomicfu", + ":transformJvmTestAtomicfu", + ":compileKotlinJs", + ":transformJsMainAtomicfu" + ), + excludedTasks = emptyList() + ) + + @Test + fun testClasspath() { + runner.build() + checkJvmCompilationClasspath( + originalClassFile = "build/classes/kotlin/jvm/main/IntArithmetic.class", + transformedClassFile = "build/classes/atomicfu/jvm/main/IntArithmetic.class" + ) + checkJsCompilationClasspath() + } + + @Test + fun testAtomicfuReferences() { + runner.build() + checkBytecode("build/classes/atomicfu/jvm/main/IntArithmetic.class") + } +} + +/** + * Test that ensures correctness of `atomicfu-gradle-plugin` application to the MPP project, + * - JVM IR compiler plugin transformation (kotlinx.atomicfu.enableJvmIrTransformation=true) + * - no post-compilation bytecode transformation tasks are created + * - post-compilation js file transformation task created (as only JVM IR transformation applied, js is transformed in legacy mode) + * - no `kotlinx/atomicfu` references are left in the transformed bytecode. + */ +class MppJvmIrTransformationTest : BaseKotlinGradleTest("mpp-simple") { + + override fun BaseKotlinScope.createProject() { + buildGradleKts { + resolve("projects/mpp-simple/mpp-simple.gradle.kts") + } + settingsGradleKts { + resolve("projects/mpp-simple/settings.gradle.kts") + } + gradleProperties { + resolve("projects/mpp-simple/gradle.properties_jvm") + } + dir("src/commonMain/kotlin") {} + kotlin("IntArithmetic.kt", "commonMain") { + resolve("projects/mpp-simple/src/commonMain/kotlin/IntArithmetic.kt") + } + dir("src/commonTest/kotlin") {} + kotlin("ArithmeticTest.kt", "commonTest") { + resolve("projects/mpp-simple/src/commonTest/kotlin/ArithmeticTest.kt") + } + } + + @Test + fun testPluginApplication() = + checkTaskOutcomes( + executedTasks = listOf( + ":compileKotlinJvm", + ":compileTestKotlinJvm", + ":compileKotlinJs", + // legacy JS transformation + ":transformJsMainAtomicfu", + ":transformJsTestAtomicfu" + ), + excludedTasks = listOf( + ":transformJvmMainAtomicfu", + ":transformJvmTestAtomicfu" + ) + ) + + @Test + fun testAtomicfuReferences() { + runner.build() + checkBytecode("build/classes/kotlin/jvm/main/IntArithmetic.class") + } +} + +/** + * Test that ensures correctness of `atomicfu-gradle-plugin` application to the MPP project, + * - JS IR compiler plugin transformation (kotlinx.atomicfu.enableJsIrTransformation=true) + * - post-compilation bytecode transformation tasks are created (only JS IR transformation is applied, jvm is transformed in legacy mode) + * - no post-compilation js file transformation tasks are created + * - no `kotlinx/atomicfu` references are left in the transformed bytecode. + */ +class MppJsIrTransformationTest : BaseKotlinGradleTest("mpp-simple") { + + override fun BaseKotlinScope.createProject() { + buildGradleKts { + resolve("projects/mpp-simple/mpp-simple.gradle.kts") + } + settingsGradleKts { + resolve("projects/mpp-simple/settings.gradle.kts") + } + gradleProperties { + resolve("projects/mpp-simple/gradle.properties_js") + } + dir("src/commonMain/kotlin") {} + kotlin("IntArithmetic.kt", "commonMain") { + resolve("projects/mpp-simple/src/commonMain/kotlin/IntArithmetic.kt") + } + dir("src/commonTest/kotlin") {} + kotlin("ArithmeticTest.kt", "commonTest") { + resolve("projects/mpp-simple/src/commonTest/kotlin/ArithmeticTest.kt") + } + } + + @Test + fun testPluginApplication() = + checkTaskOutcomes( + executedTasks = listOf( + ":compileKotlinJvm", + ":compileTestKotlinJvm", + ":compileKotlinJs", + // legacy JVM transformation + ":transformJvmMainAtomicfu", + ":transformJvmTestAtomicfu" + ), + excludedTasks = listOf( + ":transformJsMainAtomicfu", + ":transformJsTestAtomicfu" + ) + ) + + @Test + fun testAtomicfuReferences() { + runner.build() + checkBytecode("build/classes/atomicfu/jvm/main/IntArithmetic.class") + } +} + +/** + * Test that ensures correctness of `atomicfu-gradle-plugin` application to the MPP project, + * - JS IR and JVM IR compiler plugin transformation + * - no post-compilation bytecode transformation tasks are created (only JS IR transformation is applied, jvm is transformed in legacy mode) + * - no post-compilation js file transformation tasks are created + * - no `kotlinx/atomicfu` references are left in the transformed bytecode. + */ +class MppBothIrTransformationTest : BaseKotlinGradleTest("mpp-simple") { + + override fun BaseKotlinScope.createProject() { + buildGradleKts { + resolve("projects/mpp-simple/mpp-simple.gradle.kts") + } + settingsGradleKts { + resolve("projects/mpp-simple/settings.gradle.kts") + } + gradleProperties { + resolve("projects/mpp-simple/gradle.properties_both") + } + dir("src/commonMain/kotlin") {} + kotlin("IntArithmetic.kt", "commonMain") { + resolve("projects/mpp-simple/src/commonMain/kotlin/IntArithmetic.kt") + } + dir("src/commonTest/kotlin") {} + kotlin("ArithmeticTest.kt", "commonTest") { + resolve("projects/mpp-simple/src/commonTest/kotlin/ArithmeticTest.kt") + } + } + + @Test + fun testPluginApplication() = + checkTaskOutcomes( + executedTasks = listOf( + ":compileKotlinJvm", + ":compileTestKotlinJvm", + ":compileKotlinJs" + ), + excludedTasks = listOf( + ":transformJvmMainAtomicfu", + ":transformJvmTestAtomicfu", + ":transformJsMainAtomicfu", + ":transformJsTestAtomicfu" + ) + ) + + @Test + fun testAtomicfuReferences() { + runner.build() + checkBytecode("build/classes/kotlin/jvm/main/IntArithmetic.class") + } +} diff --git a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/utils.kt b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/utils.kt deleted file mode 100644 index 2a8d0f7..0000000 --- a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/utils.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2017-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package kotlinx.atomicfu.plugin.gradle - -import org.gradle.testkit.runner.BuildResult -import org.gradle.testkit.runner.TaskOutcome -import java.io.File -import kotlin.test.assertTrue - -fun BuildResult.checkOutcomes(expected: TaskOutcome, vararg tasks: String) { - val unexpectedOutcomes = tasks - .map { it to task(it)?.outcome } - .filter { (_, outcome) -> outcome != expected } - if (unexpectedOutcomes.isNotEmpty()) { - throw AssertionError("Unexpected outcomes for tasks." + - "\nExpected: $expected." + - "\nGot:" + - "\n${unexpectedOutcomes.joinToString("\n") { (task, outcome) -> "* $task -> $outcome" }}") - - } -} - -fun File.checkExists() { - assertTrue(exists(), "File does not exist: $canonicalPath") -} - -fun File.modify(fn: (String) -> String) { - writeText(fn(readText())) -} - -fun String.checkedReplace(oldValue: String, newValue: String, ignoreCase: Boolean = false): String { - check(contains(oldValue, ignoreCase)) { "String must contain '$oldValue'" } - return replace(oldValue, newValue, ignoreCase) -}
\ No newline at end of file diff --git a/atomicfu-gradle-plugin/src/test/resources/projects/empty/build.gradle b/atomicfu-gradle-plugin/src/test/resources/projects/empty/build.gradle deleted file mode 100644 index f4add41..0000000 --- a/atomicfu-gradle-plugin/src/test/resources/projects/empty/build.gradle +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright 2017-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -apply plugin: 'kotlinx-atomicfu' -apply plugin: 'base' - -repositories { - maven { url "https://oss.sonatype.org/content/repositories/snapshots" } -}
\ No newline at end of file diff --git a/atomicfu-gradle-plugin/src/test/resources/projects/js-simple/build.gradle b/atomicfu-gradle-plugin/src/test/resources/projects/js-simple/build.gradle deleted file mode 100644 index 31dbec6..0000000 --- a/atomicfu-gradle-plugin/src/test/resources/projects/js-simple/build.gradle +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright 2017-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -apply plugin: 'kotlinx-atomicfu' -apply plugin: 'kotlin2js' - -dependencies { - compileOnly atomicfuJs - testRuntime atomicfuJs - - compile 'org.jetbrains.kotlin:kotlin-stdlib-js' - testCompile 'org.jetbrains.kotlin:kotlin-test-js' -} - -compileTestKotlin2Js.doLast { - file("$buildDir/test_compile_classpath.txt").text = classpath.join("\n") -}
\ No newline at end of file diff --git a/atomicfu-gradle-plugin/src/test/resources/projects/js-simple/js-simple.gradle.kts b/atomicfu-gradle-plugin/src/test/resources/projects/js-simple/js-simple.gradle.kts new file mode 100644 index 0000000..37a41e5 --- /dev/null +++ b/atomicfu-gradle-plugin/src/test/resources/projects/js-simple/js-simple.gradle.kts @@ -0,0 +1,38 @@ +import kotlinx.atomicfu.plugin.gradle.* + +buildscript { + dependencies { + classpath("org.jetbrains.kotlinx:atomicfu-gradle-plugin:0.17.0") + } +} + +plugins { + kotlin("js") +} + +apply(plugin = "kotlinx-atomicfu") + +repositories { + mavenLocal() + mavenCentral() +} + +dependencies { + implementation(kotlin("stdlib-js")) + implementation(kotlin("test-junit")) + implementation("org.jetbrains.kotlin:kotlin-test-js") +} + +kotlin { + js { + nodejs() + } + + tasks.named("compileTestKotlinJs") { + doLast { + file("$buildDir/test_compile_js_classpath.txt").writeText( + target.compilations["test"].compileDependencyFiles.joinToString("\n") + ) + } + } +} diff --git a/atomicfu-gradle-plugin/src/test/resources/projects/js-simple/settings.gradle.kts b/atomicfu-gradle-plugin/src/test/resources/projects/js-simple/settings.gradle.kts new file mode 100644 index 0000000..bd39e74 --- /dev/null +++ b/atomicfu-gradle-plugin/src/test/resources/projects/js-simple/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "js-simple"
\ No newline at end of file diff --git a/atomicfu-gradle-plugin/src/test/resources/projects/jvm-simple/build.gradle b/atomicfu-gradle-plugin/src/test/resources/projects/jvm-simple/build.gradle deleted file mode 100644 index 7e21215..0000000 --- a/atomicfu-gradle-plugin/src/test/resources/projects/jvm-simple/build.gradle +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2017-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -apply plugin: 'kotlinx-atomicfu' -apply plugin: 'kotlin' - -// This flag is enabled to be able using JVM IR compiled dependencies (when build is ran with -Penable_jvm_ir) -kotlin.target.compilations.all { - kotlinOptions.freeCompilerArgs += '-Xallow-jvm-ir-dependencies' -} - -dependencies { - compileOnly atomicfuJvm - testRuntime atomicfuJvm - - compile 'org.jetbrains.kotlin:kotlin-stdlib' - - testCompile 'org.jetbrains.kotlin:kotlin-test' - testCompile 'org.jetbrains.kotlin:kotlin-test-junit' - testCompile 'junit:junit:4.12' -} - -compileTestKotlin.doLast { - file("$buildDir/test_compile_classpath.txt").text = classpath.join("\n") -} - -test.doLast { - file("$buildDir/test_runtime_classpath.txt").text = classpath.join("\n") -}
\ No newline at end of file diff --git a/atomicfu-gradle-plugin/src/test/resources/projects/jvm-simple/gradle.properties b/atomicfu-gradle-plugin/src/test/resources/projects/jvm-simple/gradle.properties new file mode 100644 index 0000000..fa37a2c --- /dev/null +++ b/atomicfu-gradle-plugin/src/test/resources/projects/jvm-simple/gradle.properties @@ -0,0 +1 @@ +kotlinx.atomicfu.enableJvmIrTransformation=true diff --git a/atomicfu-gradle-plugin/src/test/resources/projects/jvm-simple/jvm-simple.gradle.kts b/atomicfu-gradle-plugin/src/test/resources/projects/jvm-simple/jvm-simple.gradle.kts new file mode 100644 index 0000000..db644ef --- /dev/null +++ b/atomicfu-gradle-plugin/src/test/resources/projects/jvm-simple/jvm-simple.gradle.kts @@ -0,0 +1,41 @@ +import org.gradle.api.tasks.compile.* +import org.jetbrains.kotlin.gradle.plugin.* + +buildscript { + dependencies { + classpath("org.jetbrains.kotlinx:atomicfu-gradle-plugin:0.17.0") + } +} + +plugins { + kotlin("jvm") +} + +apply(plugin = "kotlinx-atomicfu") + +repositories { + mavenCentral() +} + +dependencies { + implementation(kotlin("stdlib")) + implementation(kotlin("test-junit")) +} + +kotlin { + tasks.compileTestKotlin { + doLast { + file("$buildDir/test_compile_jvm_classpath.txt").writeText( + target.compilations["test"].compileDependencyFiles.joinToString("\n") + ) + } + } + + tasks.test { + doLast { + file("$buildDir/test_runtime_jvm_classpath.txt").writeText( + (target.compilations["test"] as KotlinCompilationToRunnableFiles<*>).runtimeDependencyFiles.joinToString("\n") + ) + } + } +} diff --git a/atomicfu-gradle-plugin/src/test/resources/projects/jvm-simple/settings.gradle.kts b/atomicfu-gradle-plugin/src/test/resources/projects/jvm-simple/settings.gradle.kts new file mode 100644 index 0000000..2f5327f --- /dev/null +++ b/atomicfu-gradle-plugin/src/test/resources/projects/jvm-simple/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "jvm-simple"
\ No newline at end of file diff --git a/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/build.gradle b/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/build.gradle deleted file mode 100644 index fc95366..0000000 --- a/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/build.gradle +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2017-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -apply plugin: 'kotlinx-atomicfu' -apply plugin: 'kotlin-multiplatform' - -kotlin { - // This flag is enabled to be able using JVM IR compiled dependencies (when build is ran with -Penable_jvm_ir) - jvm() { - compilations.all { - kotlinOptions.freeCompilerArgs += '-Xallow-jvm-ir-dependencies' - } - } - js() - - sourceSets { - commonMain.dependencies { - implementation 'org.jetbrains.kotlin:kotlin-stdlib-common' - compileOnly atomicfuMetadata - - } - commonTest.dependencies { - implementation 'org.jetbrains.kotlin:kotlin-test-common' - implementation 'org.jetbrains.kotlin:kotlin-test-annotations-common' - runtimeOnly atomicfuMetadata - - } - jsMain.dependencies { - implementation 'org.jetbrains.kotlin:kotlin-stdlib-js' - compileOnly atomicfuJs - - } - jsTest.dependencies { - implementation 'org.jetbrains.kotlin:kotlin-test-js' - runtimeOnly atomicfuJs - } - jvmMain.dependencies { - implementation 'org.jetbrains.kotlin:kotlin-stdlib' - compileOnly atomicfuJvm - } - jvmTest.dependencies { - implementation 'org.jetbrains.kotlin:kotlin-test' - implementation 'org.jetbrains.kotlin:kotlin-test-junit' - implementation "junit:junit:4.12" - runtimeOnly atomicfuJvm - } - } -} - -def File classpathFile(String platform, String fileName) { - def dir = file("$buildDir/classpath/$platform") - dir.mkdirs() - return file("$dir/$fileName") -} - - -compileTestKotlinJvm.doLast { - classpathFile("jvm", "test_compile.txt").text = classpath.files.join("\n") -} - -jvmTest.doLast { - classpathFile("jvm", "test_runtime.txt").text = classpath.files.join("\n") -} - - -compileTestKotlinJs.doLast { - classpathFile("js", "test_compile.txt").text = classpath.files.join("\n") -} - -jsTest.dependsOn(":compileTestKotlinJs") -jsTest.dependsOn(":transformJsTestAtomicfu") -check.dependsOn(":jsTest")
\ No newline at end of file diff --git a/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/gradle.properties_both b/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/gradle.properties_both new file mode 100644 index 0000000..5d28ccd --- /dev/null +++ b/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/gradle.properties_both @@ -0,0 +1,3 @@ +kotlin.js.compiler=ir +kotlinx.atomicfu.enableJvmIrTransformation=true +kotlinx.atomicfu.enableJsIrTransformation=true diff --git a/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/gradle.properties_js b/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/gradle.properties_js new file mode 100644 index 0000000..b57875b --- /dev/null +++ b/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/gradle.properties_js @@ -0,0 +1,2 @@ +kotlin.js.compiler=ir +kotlinx.atomicfu.enableJsIrTransformation=true diff --git a/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/gradle.properties_jvm b/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/gradle.properties_jvm new file mode 100644 index 0000000..fa37a2c --- /dev/null +++ b/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/gradle.properties_jvm @@ -0,0 +1 @@ +kotlinx.atomicfu.enableJvmIrTransformation=true diff --git a/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/mpp-simple.gradle.kts b/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/mpp-simple.gradle.kts new file mode 100644 index 0000000..ed15d3d --- /dev/null +++ b/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/mpp-simple.gradle.kts @@ -0,0 +1,90 @@ +import org.jetbrains.kotlin.gradle.plugin.* + +buildscript { + dependencies { + classpath("org.jetbrains.kotlinx:atomicfu-gradle-plugin:0.17.0") + } +} + +plugins { + kotlin("multiplatform") +} + +apply(plugin = "kotlinx-atomicfu") + +repositories { + mavenCentral() +} + +kotlin { + targets { + jvm { + compilations.all { + kotlinOptions.jvmTarget = "1.8" + } + testRuns["test"].executionTask.configure { + useJUnit() + } + } + js { + nodejs() + } + } + sourceSets { + val commonMain by getting { + dependencies { + implementation("org.jetbrains.kotlin:kotlin-stdlib-common") + } + } + val commonTest by getting { + dependencies { + implementation(kotlin("test-common")) + implementation(kotlin("test-annotations-common")) + } + } + val jvmMain by getting { + dependencies { + implementation(kotlin("stdlib")) + } + } + val jvmTest by getting { + dependencies { + implementation(kotlin("test-junit")) + } + } + val jsMain by getting { + dependencies { + implementation("org.jetbrains.kotlin:kotlin-stdlib-js") + } + } + val jsTest by getting { + dependencies { + implementation("org.jetbrains.kotlin:kotlin-test-js") + } + } + } + + tasks.named("compileTestKotlinJvm") { + doLast { + file("$buildDir/test_compile_jvm_classpath.txt").writeText( + targets["jvm"].compilations["test"].compileDependencyFiles.joinToString("\n") + ) + } + } + + tasks.named("jvmTest") { + doLast { + file("$buildDir/test_runtime_jvm_classpath.txt").writeText( + (targets["jvm"].compilations["test"] as KotlinCompilationToRunnableFiles).runtimeDependencyFiles.joinToString("\n") + ) + } + } + + tasks.named("compileTestKotlinJs") { + doLast { + file("$buildDir/test_compile_js_classpath.txt").writeText( + targets["js"].compilations["test"].compileDependencyFiles.joinToString("\n") + ) + } + } +} diff --git a/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/settings.gradle.kts b/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/settings.gradle.kts new file mode 100644 index 0000000..5a4e5ab --- /dev/null +++ b/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "mpp-simple"
\ No newline at end of file |