Pill: Introduce pill{} extension to set extended Pill configuration

Also introduce the flavor concept which allows to specify what part of Kotlin project should be imported.
This commit is contained in:
Yan Zhulanow
2018-04-20 18:45:23 +03:00
parent a57869993d
commit ba5836d666
19 changed files with 133 additions and 56 deletions
+3 -3
View File
@@ -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"
+3 -3
View File
@@ -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"
+1 -1
View File
@@ -12,4 +12,4 @@ class DependencyMapper(
class MappedDependency(val main: PDependency, val deferred: List<PDependency> = emptyList())
class ParserContext(val dependencyMappers: List<DependencyMapper>)
class ParserContext(val dependencyMappers: List<DependencyMapper>, val variant: PillExtension.Variant)
@@ -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<Variant>() },
// 'BASE' if the "jps-compatible" plugin is applied, 'NONE' otherwise
DEFAULT() { override val includes = emptySet<Variant>() };
abstract val includes: Set<Variant>
}
open var variant: Variant = Variant.DEFAULT
open var importAsLibrary: Boolean = false
open var libraryPath: File? = null
set(v) {
importAsLibrary = true
field = v
}
}
@@ -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") {
+24 -26
View File
@@ -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<PLibrary>, 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<PModule> {
}
}
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<POrderRoot>): List<POrderRoot> {
val dependenciesByScope = roots.groupBy { it.scope }.mapValues { it.value.mapTo(mutableSetOf()) { it.dependency } }
fun depenciesFor(scope: Scope) = dependenciesByScope[scope] ?: emptySet<PDependency>()
fun dependenciesFor(scope: Scope) = dependenciesByScope[scope] ?: emptySet<PDependency>()
val result = mutableSetOf<POrderRoot>()
for (root in roots.distinct()) {
@@ -325,16 +323,16 @@ private fun removeDuplicates(roots: List<POrderRoot>): List<POrderRoot> {
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<POrderRoot>): List<POrderRoot> {
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<Pair<ResolvedConfiguration, Scope>>.collectDependencies(): List<DependencyInfo> {
val dependencies = mutableListOf<DependencyInfo>()
@@ -355,7 +353,7 @@ fun List<Pair<ResolvedConfiguration, Scope>>.collectDependencies(): List<Depende
for ((configuration, scope) in this) {
for (dependency in configuration.firstLevelModuleDependencies) {
unprocessed += DependencyInfo(configuration, scope, dependency)
unprocessed += DependencyInfo(scope, dependency)
}
}
@@ -371,7 +369,7 @@ fun List<Pair<ResolvedConfiguration, Scope>>.collectDependencies(): List<Depende
continue
}
unprocessed += DependencyInfo(info.configuration, info.scope, child)
unprocessed += DependencyInfo(info.scope, child)
}
}
+1 -1
View File
@@ -17,7 +17,7 @@ interface PathContext {
}
}
class ProjectContext private constructor(val projectDir: File) : PathContext {
class ProjectContext private constructor(private val projectDir: File) : PathContext {
constructor(project: PProject) : this(project.rootDirectory)
constructor(project: Project) : this(project.projectDir)
+28 -11
View File
@@ -1,3 +1,4 @@
@file:Suppress("PackageDirectoryMismatch")
package org.jetbrains.kotlin.pill
import org.gradle.api.Plugin
@@ -10,16 +11,15 @@ import shadow.org.jdom2.output.Format
import shadow.org.jdom2.output.XMLOutputter
import java.io.File
class JpsCompatibleBasePlugin : Plugin<Project> {
class PillConfigurablePlugin : Plugin<Project> {
override fun apply(project: Project) {
project.configurations.create(EmbeddedComponents.CONFIGURATION_NAME)
project.extensions.create("pill", PillExtension::class.java)
}
}
class JpsCompatiblePlugin : Plugin<Project> {
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<Project> {
}
fun getProjectLibraries(rootProject: Project): List<PLibrary> {
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<File>.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<Project> {
}
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<Project> {
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)
-1
View File
@@ -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) {
+1 -1
View File
@@ -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<String, Any>, block: xml.() -> Unit = {}) {
class xml(val name: String, private vararg val args: Pair<String, Any>, block: xml.() -> Unit = {}) {
private companion object {
fun makeXml(name: String, vararg args: Pair<String, Any>, block: xml.() -> Unit = {}): xml {
return xml(name, *args, block = block)
@@ -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")
+4 -1
View File
@@ -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')
+4 -1
View File
@@ -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
+8 -2
View File
@@ -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"
+4 -1
View File
@@ -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 {
@@ -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')
@@ -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')
+4 -1
View File
@@ -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')
+1 -1
View File
@@ -4,7 +4,7 @@ description = "Kotlin JPS plugin"
plugins {
`java-base`
id("jps-compatible-base")
id("pill-configurable")
}
val projectsToShadow = listOf(