diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 72bdb491c49..6e08963c71b 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -33,9 +33,9 @@ plugins { gradlePlugin { (plugins) { - "jps-compatible-base" { - id = "jps-compatible-base" - implementationClass = "org.jetbrains.kotlin.pill.JpsCompatibleBasePlugin" + "pill-configurable" { + id = "pill-configurable" + implementationClass = "org.jetbrains.kotlin.pill.PillConfigurablePlugin" } "jps-compatible" { id = "jps-compatible" diff --git a/buildSrc/build.gradle.kts.182 b/buildSrc/build.gradle.kts.182 index 2935ee603e3..1b0f37aa029 100644 --- a/buildSrc/build.gradle.kts.182 +++ b/buildSrc/build.gradle.kts.182 @@ -33,9 +33,9 @@ plugins { gradlePlugin { (plugins) { - "jps-compatible-base" { - id = "jps-compatible-base" - implementationClass = "org.jetbrains.kotlin.pill.JpsCompatibleBasePlugin" + "pill-configurable" { + id = "pill-configurable" + implementationClass = "org.jetbrains.kotlin.pill.PillConfigurablePlugin" } "jps-compatible" { id = "jps-compatible" diff --git a/buildSrc/src/main/kotlin/pill/context.kt b/buildSrc/src/main/kotlin/pill/context.kt index f1ff767ebf4..eae52a1e471 100644 --- a/buildSrc/src/main/kotlin/pill/context.kt +++ b/buildSrc/src/main/kotlin/pill/context.kt @@ -12,4 +12,4 @@ class DependencyMapper( class MappedDependency(val main: PDependency, val deferred: List = emptyList()) -class ParserContext(val dependencyMappers: List) \ No newline at end of file +class ParserContext(val dependencyMappers: List, val variant: PillExtension.Variant) \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/pill/extension.kt b/buildSrc/src/main/kotlin/pill/extension.kt new file mode 100644 index 00000000000..39061a4d03e --- /dev/null +++ b/buildSrc/src/main/kotlin/pill/extension.kt @@ -0,0 +1,32 @@ +@file:Suppress("PackageDirectoryMismatch") +package org.jetbrains.kotlin.pill + +import java.io.File + +open class PillExtension { + enum class Variant { + // Default variant (./gradlew pill) + BASE() { override val includes = setOf(BASE) }, + + // Full variant (./gradlew pill -Dpill.variant=full) + FULL() { override val includes = setOf(BASE, FULL) }, + + // Do not import the project to JPS model, but set some options for it + NONE() { override val includes = emptySet() }, + + // 'BASE' if the "jps-compatible" plugin is applied, 'NONE' otherwise + DEFAULT() { override val includes = emptySet() }; + + abstract val includes: Set + } + + open var variant: Variant = Variant.DEFAULT + + open var importAsLibrary: Boolean = false + + open var libraryPath: File? = null + set(v) { + importAsLibrary = true + field = v + } +} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/pill/kotlinPluginArtifact.kt b/buildSrc/src/main/kotlin/pill/kotlinPluginArtifact.kt index 7d44addc792..983e27054ea 100644 --- a/buildSrc/src/main/kotlin/pill/kotlinPluginArtifact.kt +++ b/buildSrc/src/main/kotlin/pill/kotlinPluginArtifact.kt @@ -153,7 +153,7 @@ fun generateKotlinPluginArtifactFile(rootProject: Project): PFile { .findByName(EmbeddedComponents.CONFIGURATION_NAME)?.resolvedConfiguration if (embeddedComponents != null) { - for ((_, _, dependency) in listOf(embeddedComponents to Scope.COMPILE).collectDependencies()) { + for ((_, dependency) in listOf(embeddedComponents to Scope.COMPILE).collectDependencies()) { if (dependency.configuration == "runtimeElements") { archiveForJar.add(ModuleOutput(dependency.moduleName + ".src")) } else if (dependency.configuration == "tests-jar" || dependency.configuration == "jpsTest") { diff --git a/buildSrc/src/main/kotlin/pill/parser.kt b/buildSrc/src/main/kotlin/pill/parser.kt index bbb8555da91..cfb39ecf4d6 100644 --- a/buildSrc/src/main/kotlin/pill/parser.kt +++ b/buildSrc/src/main/kotlin/pill/parser.kt @@ -11,6 +11,7 @@ import org.gradle.api.file.SourceDirectorySet import org.gradle.api.internal.HasConvention import org.jetbrains.kotlin.pill.POrderRoot.* import org.jetbrains.kotlin.pill.PSourceRoot.* +import org.jetbrains.kotlin.pill.PillExtension.* import java.io.File import java.util.LinkedList @@ -43,11 +44,7 @@ data class PSourceRoot( val path: File, val kind: Kind ) { - enum class Kind { - PRODUCTION, TEST, RESOURCES, TEST_RESOURCES; - - val isResources get() = this == RESOURCES || this == TEST_RESOURCES - } + enum class Kind { PRODUCTION, TEST, RESOURCES, TEST_RESOURCES } } data class POrderRoot( @@ -83,8 +80,14 @@ fun parse(project: Project, libraries: List, context: ParserContext): error("$project is not a root project") } + fun Project.matchesSelectedVariant(): Boolean { + val extension = this.extensions.findByType(PillExtension::class.java) ?: return true + val projectVariant = extension.variant.takeUnless { it == Variant.DEFAULT } ?: Variant.BASE + return projectVariant in context.variant.includes + } + val modules = project.allprojects - .filter { it.plugins.hasPlugin(JpsCompatiblePlugin::class.java) } + .filter { it.plugins.hasPlugin(JpsCompatiblePlugin::class.java) && it.matchesSelectedVariant() } .flatMap { parseModules(it) } return PProject("Kotlin", project.projectDir, modules, libraries) @@ -162,8 +165,8 @@ private fun ParserContext.parseModules(project: Project): List { } } - val mainModuleFileRelativePath = when { - project == project.rootProject -> File(project.rootProject.projectDir, project.name + ".iml") + val mainModuleFileRelativePath = when (project) { + project.rootProject -> File(project.rootProject.projectDir, project.name + ".iml") else -> getModuleFile() } @@ -268,7 +271,7 @@ private fun ParserContext.parseDependencies(project: Project, forTests: Boolean) return configurations } - nextDependency@ for ((configuration, scope, dependency) in collectConfigurations().collectDependencies()) { + nextDependency@ for ((scope, dependency) in collectConfigurations().collectDependencies()) { for (mapper in dependencyMappers) { if (dependency.moduleGroup == mapper.group && dependency.moduleName == mapper.module @@ -277,12 +280,7 @@ private fun ParserContext.parseDependencies(project: Project, forTests: Boolean) val mappedDependency = mapper.mapping(dependency) if (mappedDependency != null) { - val orderRoot = POrderRoot(mappedDependency.main, scope) - if (mappedDependency.main is PDependency.Module) { - mainRoots += orderRoot - } else { - mainRoots += orderRoot - } + mainRoots += POrderRoot(mappedDependency.main, scope) for (deferredDep in mappedDependency.deferred) { deferredRoots += POrderRoot(deferredDep, scope) @@ -293,10 +291,10 @@ private fun ParserContext.parseDependencies(project: Project, forTests: Boolean) } } - if (dependency.configuration == "runtimeElements" && scope != Scope.TEST) { - mainRoots += POrderRoot(PDependency.Module(dependency.moduleName + ".src"), scope) + mainRoots += if (dependency.configuration == "runtimeElements" && scope != Scope.TEST) { + POrderRoot(PDependency.Module(dependency.moduleName + ".src"), scope) } else if (dependency.configuration == "tests-jar" || dependency.configuration == "jpsTest") { - mainRoots += POrderRoot( + POrderRoot( PDependency.Module(dependency.moduleName + ".test"), scope, isProductionOnTestDependency = true @@ -304,7 +302,7 @@ private fun ParserContext.parseDependencies(project: Project, forTests: Boolean) } else { val classes = dependency.moduleArtifacts.map { it.file } val library = PLibrary(dependency.moduleName, classes) - mainRoots += POrderRoot(PDependency.ModuleLibrary(library), scope) + POrderRoot(PDependency.ModuleLibrary(library), scope) } } @@ -314,7 +312,7 @@ private fun ParserContext.parseDependencies(project: Project, forTests: Boolean) private fun removeDuplicates(roots: List): List { val dependenciesByScope = roots.groupBy { it.scope }.mapValues { it.value.mapTo(mutableSetOf()) { it.dependency } } - fun depenciesFor(scope: Scope) = dependenciesByScope[scope] ?: emptySet() + fun dependenciesFor(scope: Scope) = dependenciesByScope[scope] ?: emptySet() val result = mutableSetOf() for (root in roots.distinct()) { @@ -325,16 +323,16 @@ private fun removeDuplicates(roots: List): List { continue } - if ((scope == Scope.PROVIDED || scope == Scope.RUNTIME) && dependency in depenciesFor(Scope.COMPILE)) { + if ((scope == Scope.PROVIDED || scope == Scope.RUNTIME) && dependency in dependenciesFor(Scope.COMPILE)) { continue } - if (scope == Scope.PROVIDED && dependency in depenciesFor(Scope.RUNTIME)) { + if (scope == Scope.PROVIDED && dependency in dependenciesFor(Scope.RUNTIME)) { result += POrderRoot(dependency, Scope.COMPILE) continue } - if (scope == Scope.RUNTIME && dependency in depenciesFor(Scope.PROVIDED)) { + if (scope == Scope.RUNTIME && dependency in dependenciesFor(Scope.PROVIDED)) { result += POrderRoot(dependency, Scope.COMPILE) continue } @@ -345,7 +343,7 @@ private fun removeDuplicates(roots: List): List { return result.toList() } -data class DependencyInfo(val configuration: ResolvedConfiguration, val scope: Scope, val dependency: ResolvedDependency) +data class DependencyInfo(val scope: Scope, val dependency: ResolvedDependency) fun List>.collectDependencies(): List { val dependencies = mutableListOf() @@ -355,7 +353,7 @@ fun List>.collectDependencies(): List>.collectDependencies(): List { +class PillConfigurablePlugin : Plugin { override fun apply(project: Project) { project.configurations.create(EmbeddedComponents.CONFIGURATION_NAME) + project.extensions.create("pill", PillExtension::class.java) } } class JpsCompatiblePlugin : Plugin { companion object { - private const val JPS_LIBRARY_PATH = "jpsLibraryPath" - private fun mapper(module: String, vararg configurations: String): DependencyMapper { return DependencyMapper("org.jetbrains.kotlin", module, *configurations) { MappedDependency(PDependency.Library(module)) } } @@ -47,21 +47,24 @@ class JpsCompatiblePlugin : Plugin { } fun getProjectLibraries(rootProject: Project): List { + val distLibDir = File(rootProject.extra["distLibDir"].toString()) fun distJar(name: String) = File(rootProject.projectDir, "dist/kotlinc/lib/$name.jar") - fun projectFile(path: String) = File(rootProject.projectDir, path) val libraries = rootProject.allprojects - .filter { it.extra.has(JPS_LIBRARY_PATH) } - .map { library -> - val libraryPath = library.extra.get(JPS_LIBRARY_PATH).toString() + .mapNotNull { library -> + val libraryExtension = library.extensions.findByType(PillExtension::class.java) + ?.takeIf { it.importAsLibrary } + ?: return@mapNotNull null + + val libraryPath = libraryExtension.libraryPath ?: distLibDir val archivesBaseName = library.convention.findPlugin(BasePluginConvention::class.java)?.archivesBaseName ?: library.name fun List.filterExisting() = filter { it.exists() } PLibrary( library.name, - classes = listOf(File(libraryPath, archivesBaseName + ".jar")).filterExisting(), - sources = listOf(File(libraryPath, archivesBaseName + "-sources.jar")).filterExisting() + classes = listOf(File(libraryPath, "$archivesBaseName.jar")).filterExisting(), + sources = listOf(File(libraryPath, "$archivesBaseName-sources.jar")).filterExisting() ) } @@ -70,7 +73,7 @@ class JpsCompatiblePlugin : Plugin { } override fun apply(project: Project) { - project.plugins.apply(JpsCompatibleBasePlugin::class.java) + project.plugins.apply(PillConfigurablePlugin::class.java) // 'jpsTest' does not require the 'tests-jar' artifact project.configurations.create("jpsTest") @@ -103,8 +106,22 @@ class JpsCompatiblePlugin : Plugin { private fun pill(rootProject: Project) { initEnvironment(rootProject) + val variantOptionValue = System.getProperty("pill.variant", "base").toUpperCase() + val variant = PillExtension.Variant.values().firstOrNull { it.name == variantOptionValue } + ?: run { + rootProject.logger.error("Invalid variant name: $variantOptionValue") + return + } + + rootProject.logger.lifecycle("Pill: Setting up project for the '${variant.name.toLowerCase()}' variant...") + + if (variant == PillExtension.Variant.NONE || variant == PillExtension.Variant.DEFAULT) { + rootProject.logger.error("'none' and 'default' should not be passed as a Pill variant property value") + return + } + val projectLibraries = getProjectLibraries(rootProject) - val parserContext = ParserContext(getDependencyMappers(projectLibraries)) + val parserContext = ParserContext(getDependencyMappers(projectLibraries), variant) val jpsProject = parse(rootProject, projectLibraries, parserContext) .mapLibraries(this::attachPlatformSources, this::attachAsmSources) diff --git a/buildSrc/src/main/kotlin/pill/render.kt b/buildSrc/src/main/kotlin/pill/render.kt index 15422798086..46c6dc7518a 100644 --- a/buildSrc/src/main/kotlin/pill/render.kt +++ b/buildSrc/src/main/kotlin/pill/render.kt @@ -98,7 +98,6 @@ private fun renderModule(project: PProject, module: PModule) = PFile( "name" to dependency.name, "level" to "project" ) - else -> error("Unsupported dependency type: $dependency") } if (dependency is PDependency.Module && orderRoot.isProductionOnTestDependency) { diff --git a/buildSrc/src/main/kotlin/pill/xml.kt b/buildSrc/src/main/kotlin/pill/xml.kt index 4b325bf6bb7..71fe9504348 100644 --- a/buildSrc/src/main/kotlin/pill/xml.kt +++ b/buildSrc/src/main/kotlin/pill/xml.kt @@ -6,7 +6,7 @@ import shadow.org.jdom2.Element import shadow.org.jdom2.output.Format import shadow.org.jdom2.output.XMLOutputter -class xml(val name: String, vararg val args: Pair, block: xml.() -> Unit = {}) { +class xml(val name: String, private vararg val args: Pair, block: xml.() -> Unit = {}) { private companion object { fun makeXml(name: String, vararg args: Pair, block: xml.() -> Unit = {}): xml { return xml(name, *args, block = block) diff --git a/custom-dependencies/protobuf-relocated/build.gradle.kts b/custom-dependencies/protobuf-relocated/build.gradle.kts index e36d6e4fd45..4e20d76d49c 100644 --- a/custom-dependencies/protobuf-relocated/build.gradle.kts +++ b/custom-dependencies/protobuf-relocated/build.gradle.kts @@ -3,6 +3,7 @@ import java.io.File plugins { base + id("pill-configurable") } val baseProtobuf by configurations.creating @@ -18,7 +19,9 @@ val renamedSources = "$buildDir/renamedSrc/" val outputJarsPath = "$buildDir/libs" val artifactBaseName = "protobuf-java-relocated" -val jpsLibraryPath by extra(outputJarsPath) +pill { + libraryPath = File(outputJarsPath) +} setProperty("archivesBaseName", "$artifactBaseName-$protobufVersion") diff --git a/libraries/kotlin.test/junit/build.gradle b/libraries/kotlin.test/junit/build.gradle index 9e1f566d570..f0d541f60e4 100644 --- a/libraries/kotlin.test/junit/build.gradle +++ b/libraries/kotlin.test/junit/build.gradle @@ -1,12 +1,15 @@ description = 'Kotlin Test JUnit' apply plugin: 'kotlin-platform-jvm' +apply plugin: 'pill-configurable' configureJvm6Project(project) configureDist(project) configurePublishing(project) -project.ext["jpsLibraryPath"] = rootProject.distLibDir +pill { + importAsLibrary = true +} dependencies { expectedBy project(':kotlin-test:kotlin-test-annotations-common') diff --git a/libraries/kotlin.test/jvm/build.gradle b/libraries/kotlin.test/jvm/build.gradle index 885a45628a1..32563ea119b 100644 --- a/libraries/kotlin.test/jvm/build.gradle +++ b/libraries/kotlin.test/jvm/build.gradle @@ -1,12 +1,15 @@ description = 'Kotlin Test' apply plugin: 'kotlin-platform-jvm' +apply plugin: 'pill-configurable' configureJvm6Project(project) configureDist(project) configurePublishing(project) -project.ext["jpsLibraryPath"] = rootProject.distLibDir +pill { + importAsLibrary = true +} sourceSets { java9 diff --git a/libraries/reflect/build.gradle.kts b/libraries/reflect/build.gradle.kts index 54c818a7e18..365a96f7aea 100644 --- a/libraries/reflect/build.gradle.kts +++ b/libraries/reflect/build.gradle.kts @@ -3,6 +3,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import com.github.jengelman.gradle.plugins.shadow.transformers.TransformerContext import org.gradle.kotlin.dsl.extra import org.jetbrains.kotlin.metadata.jvm.JvmModuleProtoBuf +import org.jetbrains.kotlin.pill.PillExtension import proguard.gradle.ProGuardTask import shadow.org.apache.tools.zip.ZipEntry import shadow.org.apache.tools.zip.ZipOutputStream @@ -12,12 +13,17 @@ import java.io.DataOutputStream description = "Kotlin Full Reflection Library" -plugins { java } +plugins { + java + id("pill-configurable") +} callGroovy("configureJavaOnlyJvm6Project", this) publish() -val jpsLibraryPath by extra(rootProject.extra["distLibDir"]) +pill { + importAsLibrary = true +} val core = "$rootDir/core" val annotationsSrc = "$buildDir/annotations" diff --git a/libraries/stdlib/jvm/build.gradle b/libraries/stdlib/jvm/build.gradle index 264e241468b..981cb010a95 100644 --- a/libraries/stdlib/jvm/build.gradle +++ b/libraries/stdlib/jvm/build.gradle @@ -1,6 +1,7 @@ description = 'Kotlin Standard Library for JVM' apply plugin: 'kotlin-platform-jvm' +apply plugin: 'pill-configurable' archivesBaseName = 'kotlin-stdlib' @@ -8,7 +9,9 @@ configureJvm6Project(project) configureDist(project) configurePublishing(project) -project.ext["jpsLibraryPath"] = rootProject.distLibDir +pill { + importAsLibrary = true +} sourceSets { annotations { diff --git a/libraries/tools/kotlin-gradle-plugin-api/build.gradle b/libraries/tools/kotlin-gradle-plugin-api/build.gradle index b128d2ddeaa..e30d085ea73 100644 --- a/libraries/tools/kotlin-gradle-plugin-api/build.gradle +++ b/libraries/tools/kotlin-gradle-plugin-api/build.gradle @@ -1,5 +1,6 @@ apply plugin: 'kotlin' apply plugin: 'maven' +apply plugin: 'jps-compatible' configureJvmProject(project) configurePublishing(project) @@ -8,6 +9,10 @@ repositories { mavenLocal() } +pill { + variant = "FULL" +} + dependencies { compile project(':kotlin-stdlib') diff --git a/libraries/tools/kotlin-gradle-plugin/build.gradle b/libraries/tools/kotlin-gradle-plugin/build.gradle index a34d7d61c9b..aad9b4e690f 100644 --- a/libraries/tools/kotlin-gradle-plugin/build.gradle +++ b/libraries/tools/kotlin-gradle-plugin/build.gradle @@ -3,6 +3,7 @@ apply plugin: 'java-gradle-plugin' apply plugin: 'kotlin' apply plugin: 'groovy' apply plugin: 'org.jetbrains.dokka' +apply plugin: 'jps-compatible' buildscript { repositories { @@ -26,6 +27,10 @@ configurations { agp25CompileOnly } +pill { + variant = "FULL" +} + dependencies { compile project(':kotlin-gradle-plugin-api') compileOnly project(':compiler') diff --git a/libraries/tools/script-runtime/build.gradle b/libraries/tools/script-runtime/build.gradle index 4d992e7322d..38b47e1ea0a 100644 --- a/libraries/tools/script-runtime/build.gradle +++ b/libraries/tools/script-runtime/build.gradle @@ -1,12 +1,15 @@ description 'Kotlin Script Runtime' apply plugin: 'kotlin' +apply plugin: 'pill-configurable' configureJvm6Project(project) configureDist(project) configurePublishing(project) -project.ext["jpsLibraryPath"] = rootProject.distLibDir +pill { + importAsLibrary = true +} dependencies { compileOnly project(path: ':kotlin-stdlib', configuration: 'distJar') diff --git a/prepare/jps-plugin/build.gradle.kts b/prepare/jps-plugin/build.gradle.kts index 22f2cd6a00c..f70f556918f 100644 --- a/prepare/jps-plugin/build.gradle.kts +++ b/prepare/jps-plugin/build.gradle.kts @@ -4,7 +4,7 @@ description = "Kotlin JPS plugin" plugins { `java-base` - id("jps-compatible-base") + id("pill-configurable") } val projectsToShadow = listOf(