@@ -9,10 +9,13 @@ import org.gradle.api.*
99import org.gradle.api.file.*
1010import org.gradle.api.internal.*
1111import org.gradle.api.plugins.*
12+ import org.gradle.api.provider.Provider
13+ import org.gradle.api.provider.ProviderFactory
1214import org.gradle.api.tasks.*
1315import org.gradle.api.tasks.compile.*
1416import org.gradle.api.tasks.testing.*
1517import org.gradle.jvm.tasks.*
18+ import org.gradle.util.*
1619import org.jetbrains.kotlin.gradle.dsl.*
1720import org.jetbrains.kotlin.gradle.dsl.KotlinCompile
1821import org.jetbrains.kotlin.gradle.plugin.*
@@ -23,6 +26,7 @@ import org.jetbrains.kotlin.gradle.targets.js.*
2326import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget
2427import org.jetbrains.kotlin.gradle.tasks.*
2528import org.jetbrains.kotlinx.atomicfu.gradle.*
29+ import javax.inject.Inject
2630
2731private const val EXTENSION_NAME = " atomicfu"
2832private const val ORIGINAL_DIR_NAME = " originalClassesDir"
@@ -34,9 +38,12 @@ private const val TEST_IMPLEMENTATION_CONFIGURATION = "testImplementation"
3438private const val ENABLE_JS_IR_TRANSFORMATION_LEGACY = " kotlinx.atomicfu.enableIrTransformation"
3539private const val ENABLE_JS_IR_TRANSFORMATION = " kotlinx.atomicfu.enableJsIrTransformation"
3640private const val ENABLE_JVM_IR_TRANSFORMATION = " kotlinx.atomicfu.enableJvmIrTransformation"
41+ private const val MIN_SUPPORTED_GRADLE_VERSION = " 7.0"
42+ private const val MIN_SUPPORTED_KGP_VERSION = " 1.7.0"
3743
3844open class AtomicFUGradlePlugin : Plugin <Project > {
3945 override fun apply (project : Project ) = project.run {
46+ checkCompatibility()
4047 val pluginVersion = rootProject.buildscript.configurations.findByName(" classpath" )
4148 ?.allDependencies?.find { it.name == " atomicfu-gradle-plugin" }?.version
4249 extensions.add(EXTENSION_NAME , AtomicFUPluginExtension (pluginVersion))
@@ -46,6 +53,24 @@ open class AtomicFUGradlePlugin : Plugin<Project> {
4653 }
4754}
4855
56+ private fun Project.checkCompatibility () {
57+ val currentGradleVersion = GradleVersion .current()
58+ val kotlinVersion = getKotlinVersion()
59+ val minSupportedVersion = GradleVersion .version(MIN_SUPPORTED_GRADLE_VERSION )
60+ if (currentGradleVersion < minSupportedVersion) {
61+ throw GradleException (
62+ " The current Gradle version is not compatible with Atomicfu gradle plugin. " +
63+ " Please use Gradle $MIN_SUPPORTED_GRADLE_VERSION or newer, or the previous version of Atomicfu gradle plugin."
64+ )
65+ }
66+ if (! kotlinVersion.atLeast(1 , 7 , 0 )) {
67+ throw GradleException (
68+ " The current Kotlin gradle plugin version is not compatible with Atomicfu gradle plugin. " +
69+ " Please use Kotlin $MIN_SUPPORTED_KGP_VERSION or newer, or the previous version of Atomicfu gradle plugin."
70+ )
71+ }
72+ }
73+
4974private fun Project.configureDependencies () {
5075 withPluginWhenEvaluatedDependencies(" kotlin" ) { version ->
5176 dependencies.add(
@@ -242,68 +267,79 @@ private fun Project.configureTransformationForTarget(target: KotlinTarget) {
242267 ? : return @compilations // skip unknown compilations
243268 val classesDirs = compilation.output.classesDirs
244269 // make copy of original classes directory
245- val originalClassesDirs: FileCollection =
246- project.files(classesDirs.from.toTypedArray()).filter { it.exists() }
270+ @Suppress(" UNCHECKED_CAST" )
271+ val compilationTask = compilation.compileTaskProvider as TaskProvider <KotlinCompileTool >
272+ val originalDestinationDirectory = project.layout.buildDirectory
273+ .dir(" classes/atomicfu-orig/${target.name} /${compilation.name} " )
274+ compilationTask.configure {
275+ if (it is Kotlin2JsCompile ) {
276+ @Suppress(" INVISIBLE_REFERENCE" , " INVISIBLE_MEMBER" , " EXPOSED_PARAMETER_TYPE" )
277+ it.defaultDestinationDirectory.value(originalDestinationDirectory)
278+ } else {
279+ it.destinationDirectory.value(originalDestinationDirectory)
280+ }
281+ }
282+ val originalClassesDirs: FileCollection = project.objects.fileCollection().from(
283+ compilationTask.flatMap { it.destinationDirectory }
284+ )
247285 originalDirsByCompilation[compilation] = originalClassesDirs
248- val transformedClassesDir =
249- project.buildDir.resolve (" classes/atomicfu/${target.name} /${compilation.name} " )
286+ val transformedClassesDir = project.layout.buildDirectory
287+ .dir (" classes/atomicfu/${target.name} /${compilation.name} " )
250288 val transformTask = when (target.platformType) {
251289 KotlinPlatformType .jvm, KotlinPlatformType .androidJvm -> {
252290 // skip transformation task if transformation is turned off or ir transformation is enabled
253291 if (! config.transformJvm || rootProject.getBooleanProperty(ENABLE_JVM_IR_TRANSFORMATION )) return @compilations
254- project.createJvmTransformTask(compilation).configureJvmTask(
255- compilation.compileDependencyFiles,
256- compilation.compileAllTaskName,
257- transformedClassesDir,
258- originalClassesDirs,
259- config
260- )
292+ project.registerJvmTransformTask(compilation)
293+ .configureJvmTask(
294+ compilation.compileDependencyFiles,
295+ compilation.compileAllTaskName,
296+ transformedClassesDir,
297+ originalClassesDirs,
298+ config
299+ )
300+ .also {
301+ compilation.defaultSourceSet.kotlin.compiledBy(it, AtomicFUTransformTask ::destinationDirectory)
302+ }
261303 }
262304 KotlinPlatformType .js -> {
263305 // skip when js transformation is not needed or when IR is transformed
264306 if (! config.transformJs || (needsJsIrTransformation(target))) {
265307 return @compilations
266308 }
267- project.createJsTransformTask(compilation).configureJsTask(
268- compilation.compileAllTaskName,
269- transformedClassesDir,
270- originalClassesDirs,
271- config
272- )
309+ project.registerJsTransformTask(compilation)
310+ .configureJsTask(
311+ compilation.compileAllTaskName,
312+ transformedClassesDir,
313+ originalClassesDirs,
314+ config
315+ )
316+ .also {
317+ compilation.defaultSourceSet.kotlin.compiledBy(it, AtomicFUTransformJsTask ::destinationDirectory)
318+ }
273319 }
274320 else -> error(" Unsupported transformation platform '${target.platformType} '" )
275321 }
276322 // now transformTask is responsible for compiling this source set into the classes directory
323+ compilation.defaultSourceSet.kotlin.destinationDirectory.value(transformedClassesDir)
277324 classesDirs.setFrom(transformedClassesDir)
278- classesDirs.builtBy(transformTask)
279- (tasks.findByName(target.artifactsTaskName) as ? Jar )?.apply {
280- setupJarManifest(multiRelease = config.jvmVariant.toJvmVariant() == JvmVariant .BOTH )
325+ classesDirs.setBuiltBy(listOf (transformTask))
326+ tasks.withType(Jar ::class .java).configureEach {
327+ if (name == target.artifactsTaskName) {
328+ it.setupJarManifest(multiRelease = config.jvmVariant.toJvmVariant() == JvmVariant .BOTH )
329+ }
281330 }
282331 // test should compile and run against original production binaries
283332 if (compilationType == CompilationType .TEST ) {
284333 val mainCompilation =
285334 compilation.target.compilations.getByName(KotlinCompilation .MAIN_COMPILATION_NAME )
286- val originalMainClassesDirs = project.files(
287- // use Callable because there is no guarantee that main is configured before test
288- Callable { originalDirsByCompilation[mainCompilation]!! }
335+ val originalMainClassesDirs = project.objects.fileCollection().from(
336+ mainCompilation.compileTaskProvider.flatMap { (it as KotlinCompileTool ).destinationDirectory }
289337 )
290-
291- // KGP >= 1.7.0 has breaking changes in task hierarchy:
292- // https://youtrack.jetbrains.com/issue/KT-32805#focus=Comments-27-5915479.0-0
293- val (majorVersion, minorVersion) = getKotlinPluginVersion()
294- .split(' .' )
295- .take(2 )
296- .map { it.toInt() }
297- if (majorVersion == 1 && minorVersion < 7 ) {
298- (tasks.findByName(compilation.compileKotlinTaskName) as ? AbstractCompile )?.classpath =
299- originalMainClassesDirs + compilation.compileDependencyFiles - mainCompilation.output.classesDirs
300- } else {
301- (tasks.findByName(compilation.compileKotlinTaskName) as ? AbstractKotlinCompileTool <* >)
302- ?.libraries
303- ?.setFrom(
304- originalMainClassesDirs + compilation.compileDependencyFiles - mainCompilation.output.classesDirs
305- )
306- }
338+ (tasks.findByName(compilation.compileKotlinTaskName) as ? AbstractKotlinCompileTool <* >)
339+ ?.libraries
340+ ?.setFrom(
341+ originalMainClassesDirs + compilation.compileDependencyFiles
342+ )
307343
308344 (tasks.findByName(" ${target.name}${compilation.name.capitalize()} " ) as ? Test )?.classpath =
309345 originalMainClassesDirs + (compilation as KotlinCompilationToRunnableFiles ).runtimeDependencyFiles - mainCompilation.output.classesDirs
@@ -381,48 +417,49 @@ fun Project.configureMultiplatformPluginDependencies(version: String) {
381417
382418fun String.toJvmVariant (): JvmVariant = enumValueOf(toUpperCase(Locale .US ))
383419
384- fun Project.createJvmTransformTask (compilation : KotlinCompilation <* >): AtomicFUTransformTask =
385- tasks.create (
420+ fun Project.registerJvmTransformTask (compilation : KotlinCompilation <* >): TaskProvider < AtomicFUTransformTask > =
421+ tasks.register (
386422 " transform${compilation.target.name.capitalize()}${compilation.name.capitalize()} Atomicfu" ,
387423 AtomicFUTransformTask ::class .java
388424 )
389425
390- fun Project.createJsTransformTask (compilation : KotlinCompilation <* >): AtomicFUTransformJsTask =
391- tasks.create (
426+ fun Project.registerJsTransformTask (compilation : KotlinCompilation <* >): TaskProvider < AtomicFUTransformJsTask > =
427+ tasks.register (
392428 " transform${compilation.target.name.capitalize()}${compilation.name.capitalize()} Atomicfu" ,
393429 AtomicFUTransformJsTask ::class .java
394430 )
395431
396- fun Project.createJvmTransformTask (sourceSet : SourceSet ): AtomicFUTransformTask =
397- tasks.create(sourceSet.getTaskName(" transform" , " atomicfuClasses" ), AtomicFUTransformTask ::class .java)
398-
399- fun AtomicFUTransformTask.configureJvmTask (
432+ fun TaskProvider<AtomicFUTransformTask>.configureJvmTask (
400433 classpath : FileCollection ,
401434 classesTaskName : String ,
402- transformedClassesDir : File ,
435+ transformedClassesDir : Provider < Directory > ,
403436 originalClassesDir : FileCollection ,
404437 config : AtomicFUPluginExtension
405- ): ConventionTask =
438+ ): TaskProvider < AtomicFUTransformTask > =
406439 apply {
407- dependsOn(classesTaskName)
408- classPath = classpath
409- inputFiles = originalClassesDir
410- outputDir = transformedClassesDir
411- jvmVariant = config.jvmVariant
412- verbose = config.verbose
440+ configure {
441+ it.dependsOn(classesTaskName)
442+ it.classPath = classpath
443+ it.inputFiles = originalClassesDir
444+ it.destinationDirectory.value(transformedClassesDir)
445+ it.jvmVariant = config.jvmVariant
446+ it.verbose = config.verbose
447+ }
413448 }
414449
415- fun AtomicFUTransformJsTask.configureJsTask (
450+ fun TaskProvider< AtomicFUTransformJsTask> .configureJsTask (
416451 classesTaskName : String ,
417- transformedClassesDir : File ,
452+ transformedClassesDir : Provider < Directory > ,
418453 originalClassesDir : FileCollection ,
419454 config : AtomicFUPluginExtension
420- ): ConventionTask =
455+ ): TaskProvider < AtomicFUTransformJsTask > =
421456 apply {
422- dependsOn(classesTaskName)
423- inputFiles = originalClassesDir
424- outputDir = transformedClassesDir
425- verbose = config.verbose
457+ configure {
458+ it.dependsOn(classesTaskName)
459+ it.inputFiles = originalClassesDir
460+ it.destinationDirectory.value(transformedClassesDir)
461+ it.verbose = config.verbose
462+ }
426463 }
427464
428465fun Jar.setupJarManifest (multiRelease : Boolean ) {
@@ -445,13 +482,29 @@ class AtomicFUPluginExtension(pluginVersion: String?) {
445482}
446483
447484@CacheableTask
448- open class AtomicFUTransformTask : ConventionTask () {
485+ abstract class AtomicFUTransformTask : ConventionTask () {
486+ @get:Inject
487+ internal abstract val providerFactory: ProviderFactory
488+
489+ @get:Inject
490+ internal abstract val projectLayout: ProjectLayout
491+
449492 @PathSensitive(PathSensitivity .RELATIVE )
450493 @InputFiles
451494 lateinit var inputFiles: FileCollection
452495
453- @OutputDirectory
454- lateinit var outputDir: File
496+ @Suppress(" unused" )
497+ @Deprecated(
498+ message = " Replaced with 'destinationDirectory'" ,
499+ replaceWith = ReplaceWith (" destinationDirectory" )
500+ )
501+ @get:Internal
502+ var outputDir: File
503+ get() = destinationDirectory.get().asFile
504+ set(value) { destinationDirectory.value(projectLayout.dir(providerFactory.provider { value })) }
505+
506+ @get:OutputDirectory
507+ abstract val destinationDirectory: DirectoryProperty
455508
456509 @Classpath
457510 @InputFiles
@@ -467,7 +520,7 @@ open class AtomicFUTransformTask : ConventionTask() {
467520 fun transform () {
468521 val cp = classPath.files.map { it.absolutePath }
469522 inputFiles.files.forEach { inputDir ->
470- AtomicFUTransformer (cp, inputDir, outputDir ).let { t ->
523+ AtomicFUTransformer (cp, inputDir, destinationDirectory.get().asFile ).let { t ->
471524 t.jvmVariant = jvmVariant.toJvmVariant()
472525 t.verbose = verbose
473526 t.transform()
@@ -477,21 +530,38 @@ open class AtomicFUTransformTask : ConventionTask() {
477530}
478531
479532@CacheableTask
480- open class AtomicFUTransformJsTask : ConventionTask () {
533+ abstract class AtomicFUTransformJsTask : ConventionTask () {
534+
535+ @get:Inject
536+ internal abstract val providerFactory: ProviderFactory
537+
538+ @get:Inject
539+ internal abstract val projectLayout: ProjectLayout
540+
481541 @PathSensitive(PathSensitivity .RELATIVE )
482542 @InputFiles
483543 lateinit var inputFiles: FileCollection
484544
485- @OutputDirectory
486- lateinit var outputDir: File
545+ @Suppress(" unused" )
546+ @Deprecated(
547+ message = " Replaced with 'destinationDirectory'" ,
548+ replaceWith = ReplaceWith (" destinationDirectory" )
549+ )
550+ @get:Internal
551+ var outputDir: File
552+ get() = destinationDirectory.get().asFile
553+ set(value) { destinationDirectory.value(projectLayout.dir(providerFactory.provider { value })) }
554+
555+ @get:OutputDirectory
556+ abstract val destinationDirectory: DirectoryProperty
487557
488558 @Input
489559 var verbose = false
490560
491561 @TaskAction
492562 fun transform () {
493563 inputFiles.files.forEach { inputDir ->
494- AtomicFUTransformerJS (inputDir, outputDir ).let { t ->
564+ AtomicFUTransformerJS (inputDir, destinationDirectory.get().asFile ).let { t ->
495565 t.verbose = verbose
496566 t.transform()
497567 }
0 commit comments