From 73813aef2353626b4c573202ae478b0cebc9be88 Mon Sep 17 00:00:00 2001 From: Yan Zhulanow Date: Fri, 24 Jan 2020 22:19:43 +0900 Subject: [PATCH] Pill: Support all Gradle source sets, not just main/test --- buildSrc/build.gradle.kts | 4 - buildSrc/src/main/kotlin/pill/context.kt | 33 -- buildSrc/src/main/kotlin/pill/dependencies.kt | 94 ---- buildSrc/src/main/kotlin/pill/extension.kt | 30 +- .../main/kotlin/pill/kotlinPluginArtifact.kt | 58 ++- buildSrc/src/main/kotlin/pill/parser.kt | 408 +++++++++--------- buildSrc/src/main/kotlin/pill/pathContext.kt | 8 +- buildSrc/src/main/kotlin/pill/plugin.kt | 278 ++++++++---- buildSrc/src/main/kotlin/pill/render.kt | 18 +- buildSrc/src/main/kotlin/pill/xml.kt | 7 +- .../test/JUnit3RunnerWithInnersForJPS.java | 2 +- .../annotations-common/build.gradle | 5 - libraries/kotlin.test/common/build.gradle | 5 - libraries/kotlin.test/junit/build.gradle | 5 - libraries/kotlin.test/jvm/build.gradle | 5 - libraries/reflect/build.gradle.kts | 5 - libraries/stdlib/common/build.gradle | 5 - libraries/stdlib/jdk7/build.gradle | 5 - libraries/stdlib/jdk8/build.gradle | 5 - libraries/stdlib/jvm/build.gradle | 5 - .../tools/kotlin-annotations-jvm/build.gradle | 5 - .../kotlin-gradle-statistics/build.gradle.kts | 1 + libraries/tools/script-runtime/build.gradle | 5 - prepare/jps-plugin/build.gradle.kts | 1 - 24 files changed, 446 insertions(+), 551 deletions(-) delete mode 100644 buildSrc/src/main/kotlin/pill/context.kt delete mode 100644 buildSrc/src/main/kotlin/pill/dependencies.kt diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 77db0e187be..963e804ec71 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -46,10 +46,6 @@ plugins { gradlePlugin { plugins { - register("pill-configurable") { - id = "pill-configurable" - implementationClass = "org.jetbrains.kotlin.pill.PillConfigurablePlugin" - } register("jps-compatible") { id = "jps-compatible" implementationClass = "org.jetbrains.kotlin.pill.JpsCompatiblePlugin" diff --git a/buildSrc/src/main/kotlin/pill/context.kt b/buildSrc/src/main/kotlin/pill/context.kt deleted file mode 100644 index 3c550a1f6f6..00000000000 --- a/buildSrc/src/main/kotlin/pill/context.kt +++ /dev/null @@ -1,33 +0,0 @@ -@file:Suppress("PackageDirectoryMismatch") -package org.jetbrains.kotlin.pill - -import org.gradle.api.artifacts.* -import org.gradle.api.artifacts.component.* - -class DependencyMapper(val predicate: (ResolvedArtifact) -> Boolean, val mapping: (ResolvedArtifact) -> MappedDependency?) { - companion object { - fun forProject(path: String, mapping: (ResolvedArtifact) -> MappedDependency?): DependencyMapper { - return DependencyMapper( - predicate = { artifact -> - val identifier = artifact.id.componentIdentifier as? ProjectComponentIdentifier - identifier?.projectPath == path - }, - mapping = mapping - ) - } - - fun forModule(group: String, module: String, version: String?, mapping: (ResolvedArtifact) -> MappedDependency?): DependencyMapper { - return DependencyMapper( - predicate = { artifact -> - val identifier = artifact.id.componentIdentifier as? ModuleComponentIdentifier - identifier?.group == group && identifier?.module == module && (version == null || identifier?.version == version) - }, - mapping = mapping - ) - } - } -} - -class MappedDependency(val main: PDependency?, val deferred: List = emptyList()) - -class ParserContext(val dependencyMappers: List, val variant: PillExtension.Variant) \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/pill/dependencies.kt b/buildSrc/src/main/kotlin/pill/dependencies.kt deleted file mode 100644 index 53bb9f914cc..00000000000 --- a/buildSrc/src/main/kotlin/pill/dependencies.kt +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -@file:Suppress("PackageDirectoryMismatch") -package org.jetbrains.kotlin.pill - -import java.io.File -import org.gradle.api.Project -import org.gradle.api.tasks.SourceSet -import org.gradle.api.artifacts.* -import org.gradle.api.artifacts.component.* - -data class PDependencies(val main: List, val deferred: List) { - fun join(): List { - return main + deferred - } -} - -fun Project.resolveDependencies( - configuration: Configuration, - forTests: Boolean, - dependencyMappers: List, - withEmbedded: Boolean = false -): PDependencies { - val dependencies = mutableListOf() - val deferred = mutableListOf() - - nextArtifact@ for (artifact in configuration.resolvedConfiguration.resolvedArtifacts) { - val identifier = artifact.id.componentIdentifier - - for (mapper in dependencyMappers) { - if (mapper.predicate(artifact)) { - val mapped = mapper.mapping(artifact) - - if (mapped != null) { - mapped.main?.let { dependencies += it } - deferred += mapped.deferred - } - - continue@nextArtifact - } - } - - fun addProjectDependency(projectPath: String) { - val project = rootProject.findProject(projectPath) ?: error("Cannot find project $projectPath") - - fun addSourceSet(name: String, suffix: String): Boolean { - val sourceSet = project.sourceSets?.findByName(name)?.takeIf { !it.allSource.isEmpty() } ?: return false - dependencies += PDependency.Module(project.pillModuleName + '.' + suffix) - return true - } - - if (forTests && artifact.classifier == "tests") { - addSourceSet(SourceSet.TEST_SOURCE_SET_NAME, "test") || addSourceSet(SourceSet.MAIN_SOURCE_SET_NAME, "src") - } else { - addSourceSet(SourceSet.MAIN_SOURCE_SET_NAME, "src") - } - - if (withEmbedded) { - val embeddedConfiguration = project.configurations.findByName(EmbeddedComponents.CONFIGURATION_NAME) - if (embeddedConfiguration != null) { - dependencies += resolveDependencies(embeddedConfiguration, forTests, dependencyMappers, withEmbedded).join() - } - } - } - - when (identifier) { - is ProjectComponentIdentifier -> addProjectDependency(identifier.projectPath) - is LibraryBinaryIdentifier -> addProjectDependency(identifier.projectPath) - is ModuleComponentIdentifier -> { - val file = artifact.file - val library = PLibrary(file.name, classes = listOf(file)) - dependencies += PDependency.ModuleLibrary(library) - } - } - } - - val existingFiles = mutableSetOf() - - for (dependency in configuration.dependencies) { - if (dependency !is SelfResolvingDependency) { - continue - } - - val files = dependency.resolve().filter { it !in existingFiles }.takeIf { it.isNotEmpty() } ?: continue - existingFiles.addAll(files) - val library = PLibrary(dependency.name, classes = files.toList()) - deferred += PDependency.ModuleLibrary(library) - } - - return PDependencies(dependencies, deferred) -} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/pill/extension.kt b/buildSrc/src/main/kotlin/pill/extension.kt index b9b0199f5a9..5306c632088 100644 --- a/buildSrc/src/main/kotlin/pill/extension.kt +++ b/buildSrc/src/main/kotlin/pill/extension.kt @@ -1,3 +1,8 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + @file:Suppress("PackageDirectoryMismatch") package org.jetbrains.kotlin.pill @@ -7,33 +12,34 @@ import org.gradle.api.Project open class PillExtension { enum class Variant { // Default variant (./gradlew pill) - BASE() { override val includes = setOf(BASE) }, + BASE() { + override val includes = setOf(BASE) + }, // Full variant (./gradlew pill -Dpill.variant=full) - FULL() { override val includes = setOf(BASE, 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() }, + NONE() { + override val includes = emptySet() + }, // 'BASE' if the "jps-compatible" plugin is applied, 'NONE' otherwise - DEFAULT() { override val includes = emptySet() }; + DEFAULT() { + override val includes = emptySet() + }; abstract val includes: Set } open var variant: Variant = Variant.DEFAULT - open var importAsLibrary: Boolean = false - open var excludedDirs: List = emptyList() + @Suppress("unused") fun Project.excludedDirs(vararg dirs: String) { excludedDirs = excludedDirs + dirs.map { File(projectDir, it) } } - - 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 d6b9ceeb04b..2921a9556f1 100644 --- a/buildSrc/src/main/kotlin/pill/kotlinPluginArtifact.kt +++ b/buildSrc/src/main/kotlin/pill/kotlinPluginArtifact.kt @@ -1,21 +1,19 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + @file:Suppress("PackageDirectoryMismatch") package org.jetbrains.kotlin.pill -import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import org.gradle.api.Project import org.gradle.api.artifacts.Configuration -import org.gradle.api.artifacts.ProjectDependency -import org.gradle.api.internal.file.copy.SingleParentCopySpec -import org.gradle.api.plugins.JavaPlugin -import org.gradle.api.tasks.Copy -import org.gradle.jvm.tasks.Jar import org.gradle.kotlin.dsl.extra import org.jetbrains.kotlin.pill.ArtifactElement.* -import org.jetbrains.kotlin.pill.POrderRoot.* import java.io.File -class PArtifact(val artifactName: String, val outputDir: File, private val contents: ArtifactElement.Root) { +class PArtifact(val artifactName: String, private val outputDir: File, private val contents: Root) { fun render(context: PathContext) = xml("component", "name" to "ArtifactManager") { xml("artifact", "name" to artifactName) { xml("output-path") { @@ -27,6 +25,10 @@ class PArtifact(val artifactName: String, val outputDir: File, private val conte } } +interface OpaqueDependencyMapper { + fun map(dependency: PDependency): List +} + sealed class ArtifactElement { private val myChildren = mutableListOf() val children get() = myChildren @@ -47,25 +49,6 @@ sealed class ArtifactElement { } } - fun getDirectory(path: String): ArtifactElement { - if (path.isEmpty()) { - return this - } - - var current: ArtifactElement = this - for (segment in path.split("/")) { - val existing = current.children.firstOrNull { it is Directory && it.name == segment } - if (existing != null) { - current = existing - continue - } - - current = Directory(segment).also { current.add(it) } - } - - return current - } - class Root : ArtifactElement() { override fun render(context: PathContext) = xml("root", "id" to "root") } @@ -107,7 +90,7 @@ sealed class ArtifactElement { } } -fun generateKotlinPluginArtifactFile(rootProject: Project, dependencyMappers: List): PFile { +fun generateKotlinPluginArtifactFile(rootProject: Project, dependencyMapper: OpaqueDependencyMapper): PFile { val root = Root() fun Project.getProject(name: String) = findProject(name) ?: error("Cannot find project $name") @@ -121,13 +104,13 @@ fun generateKotlinPluginArtifactFile(rootProject: Project, dependencyMappers: Li root.add(Directory("lib").apply { val librariesConfiguration = prepareIdeaPluginProject.configurations.getByName("libraries") - add(getArtifactElements(rootProject, librariesConfiguration, dependencyMappers, false)) + add(getArtifactElements(rootProject, librariesConfiguration, dependencyMapper, false)) add(Directory("jps").apply { val prepareJpsPluginProject = rootProject.getProject(":kotlin-jps-plugin") add(Archive(prepareJpsPluginProject.name + ".jar").apply { val jpsPluginConfiguration = prepareIdeaPluginProject.configurations.getByName("jpsPlugin") - add(getArtifactElements(rootProject, jpsPluginConfiguration, dependencyMappers, true)) + add(getArtifactElements(rootProject, jpsPluginConfiguration, dependencyMapper, true)) }) }) @@ -135,7 +118,7 @@ fun generateKotlinPluginArtifactFile(rootProject: Project, dependencyMappers: Li add(FileCopy(File(rootProject.projectDir, "resources/kotlinManifest.properties"))) val embeddedConfiguration = prepareIdeaPluginProject.configurations.getByName(EmbeddedComponents.CONFIGURATION_NAME) - add(getArtifactElements(rootProject, embeddedConfiguration, dependencyMappers, true)) + add(getArtifactElements(rootProject, embeddedConfiguration, dependencyMapper, true)) }) }) @@ -149,10 +132,10 @@ fun generateKotlinPluginArtifactFile(rootProject: Project, dependencyMappers: Li private fun getArtifactElements( rootProject: Project, configuration: Configuration, - dependencyMappers: List, + dependencyMapper: OpaqueDependencyMapper, extractDependencies: Boolean ): List { - val dependencies = rootProject.resolveDependencies(configuration, false, dependencyMappers, withEmbedded = true).join() + val dependencies = parseDependencies(configuration, dependencyMapper) val artifacts = mutableListOf() @@ -179,4 +162,13 @@ private fun getArtifactElements( } return artifacts +} + +private fun parseDependencies(configuration: Configuration, dependencyMapper: OpaqueDependencyMapper): List { + val dependencies = mutableListOf() + for (file in configuration.resolve()) { + val library = PLibrary(file.name, listOf(file)) + dependencies += dependencyMapper.map(PDependency.ModuleLibrary(library)) + } + return dependencies } \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/pill/parser.kt b/buildSrc/src/main/kotlin/pill/parser.kt index 20acdc7ef58..4209f7654b4 100644 --- a/buildSrc/src/main/kotlin/pill/parser.kt +++ b/buildSrc/src/main/kotlin/pill/parser.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -7,51 +7,63 @@ package org.jetbrains.kotlin.pill import org.gradle.api.Project -import org.gradle.api.artifacts.* import org.gradle.api.tasks.* import org.gradle.api.plugins.JavaPlugin import org.gradle.api.plugins.JavaPluginConvention -import org.gradle.kotlin.dsl.configure import org.gradle.plugins.ide.idea.IdeaPlugin import org.gradle.api.file.SourceDirectorySet import org.gradle.api.internal.HasConvention import org.gradle.api.internal.file.copy.CopySpecInternal import org.gradle.api.internal.file.copy.SingleParentCopySpec +import org.gradle.jvm.tasks.Jar import org.gradle.language.jvm.tasks.ProcessResources 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 + +class ParserContext(val variant: Variant) + +typealias OutputDir = String +typealias GradleProjectPath = String data class PProject( val name: String, val rootDirectory: File, val modules: List, - val libraries: List + val libraries: List, + val artifacts: Map> ) data class PModule( val name: String, + val path: GradleProjectPath, + val forTests: Boolean, val rootDirectory: File, val moduleFile: File, val contentRoots: List, val orderRoots: List, + val kotlinOptions: PSourceRootKotlinOptions?, val moduleForProductionSources: PModule? = null ) data class PContentRoot( val path: File, - val forTests: Boolean, val sourceRoots: List, val excludedDirectories: List ) -data class PSourceRoot( - val path: File, - val kind: Kind, - val kotlinOptions: PSourceRootKotlinOptions? -) { +data class PSourceSet( + val name: String, + val forTests: Boolean, + val sourceDirectories: List, + val resourceDirectories: List, + val kotlinOptions: PSourceRootKotlinOptions?, + val compileClasspathConfigurationName: String, + val runtimeClasspathConfigurationName: String +) + +data class PSourceRoot(val directory: File, val kind: Kind) { enum class Kind { PRODUCTION, TEST, RESOURCES, TEST_RESOURCES } } @@ -63,17 +75,7 @@ data class PSourceRootKotlinOptions( val languageVersion: String?, val jvmTarget: String?, val extraArguments: List -) { - fun intersect(other: PSourceRootKotlinOptions) = PSourceRootKotlinOptions( - if (noStdlib == other.noStdlib) noStdlib else null, - if (noReflect == other.noReflect) noReflect else null, - if (moduleName == other.moduleName) moduleName else null, - if (apiVersion == other.apiVersion) apiVersion else null, - if (languageVersion == other.languageVersion) languageVersion else null, - if (jvmTarget == other.jvmTarget) jvmTarget else null, - extraArguments.intersect(other.extraArguments).toList() - ) -} +) data class POrderRoot( val dependency: PDependency, @@ -104,7 +106,7 @@ data class PLibrary( } } -fun parse(project: Project, libraries: List, context: ParserContext): PProject = with (context) { +fun parse(project: Project, context: ParserContext): PProject = with(context) { if (project != project.rootProject) { error("$project is not a root project") } @@ -119,182 +121,199 @@ fun parse(project: Project, libraries: List, context: ParserContext): .partition { it.plugins.hasPlugin(JpsCompatiblePlugin::class.java) && it.matchesSelectedVariant() } val modules = includedProjects.flatMap { parseModules(it, excludedProjects) } + val artifacts = parseArtifacts(project) - return PProject("Kotlin", project.projectDir, modules, libraries) + return PProject("Kotlin", project.projectDir, modules, emptyList(), artifacts) } -/* - Ordering here and below is significant. - Placing 'runtime' configuration dependencies on the top make 'idea' tests to run normally. - ('idea' module has 'intellij-core' as transitive dependency, and we really need to get rid of it.) - */ -private val CONFIGURATION_MAPPING = mapOf( - listOf("runtimeClasspath") to Scope.RUNTIME, - listOf("compileClasspath", "compileOnly") to Scope.PROVIDED, - listOf("embedded") to Scope.COMPILE -) +private fun parseArtifacts(rootProject: Project): Map> { + val artifacts = HashMap>() + val additionalOutputs = HashMap>() -private val TEST_CONFIGURATION_MAPPING = mapOf( - listOf("runtimeClasspath", "testRuntimeClasspath") to Scope.RUNTIME, - listOf("compileClasspath", "testCompileClasspath", "compileOnly", "testCompileOnly") to Scope.PROVIDED, - listOf("jpsTest") to Scope.TEST -) + for (project in rootProject.allprojects) { + val sourceSets = project.sourceSets?.toList() ?: emptyList() -private fun ParserContext.parseModules(project: Project, excludedProjects: List): List { - val (productionContentRoots, testContentRoots) = parseContentRoots(project).partition { !it.forTests } + for (sourceSet in sourceSets) { + val path = makePath(project, sourceSet.name) + for (output in sourceSet.output.toList()) { + artifacts[output.absolutePath] = listOf(path) + } + + val jarTask = project.tasks.findByName(sourceSet.jarTaskName) as? Jar ?: continue + val embeddedTask = findEmbeddableTask(project, sourceSet) + + for (task in listOfNotNull(jarTask, embeddedTask)) { + val archiveFile = task.archiveFile.get().asFile + artifacts[archiveFile.absolutePath] = listOf(path) + + val additionalOutputsForSourceSet = mutableListOf() + fun process(spec: CopySpecInternal) { + spec.children.forEach { process(it) } + if (spec is SingleParentCopySpec) { + for (sourcePath in spec.sourcePaths) { + if (sourcePath is SourceSetOutput) { + additionalOutputsForSourceSet += sourcePath.classesDirs + sourcePath.resourcesDir?.let { additionalOutputsForSourceSet += it } + } + } + } + } + process(task.rootSpec) + additionalOutputs[archiveFile.absolutePath] = additionalOutputsForSourceSet.map { it.absolutePath } + } + } + } + + for ((sourceSetOutputDir, additionalOutputsForSourceSet) in additionalOutputs) { + val projectPaths = artifacts[sourceSetOutputDir] ?: error("Unknown artifact $sourceSetOutputDir") + val newPaths = projectPaths + additionalOutputsForSourceSet.mapNotNull { artifacts[it] }.flatten() + artifacts[sourceSetOutputDir] = newPaths.distinct() + } + + return artifacts +} + +private fun findEmbeddableTask(project: Project, sourceSet: SourceSet): Jar? { + val jarName = sourceSet.jarTaskName + val embeddable = "embeddable" + val embeddedName = if (jarName == "jar") embeddable else jarName.dropLast("jar".length) + embeddable.capitalize() + return project.tasks.findByName(embeddedName) as? Jar +} + +private fun makePath(project: Project, sourceSetName: String): GradleProjectPath { + return project.path + "/" + sourceSetName +} + +private fun parseModules(project: Project, excludedProjects: List): List { val modules = mutableListOf() - fun getJavaExcludedDirs() = project.plugins.findPlugin(IdeaPlugin::class.java) - ?.model?.module?.excludeDirs?.toList() ?: emptyList() - - fun getPillExcludedDirs() = project.extensions.getByType(PillExtension::class.java).excludedDirs - - val allExcludedDirs = getPillExcludedDirs() + getJavaExcludedDirs() + project.buildDir + - (if (project == project.rootProject) excludedProjects.map { it.buildDir } else emptyList()) - - var productionSourcesModule: PModule? = null - - fun getModuleFile(suffix: String = ""): File { - val relativePath = File(project.projectDir, project.pillModuleName + suffix + ".iml") - .toRelativeString(project.rootProject.projectDir) - + fun getModuleFile(name: String): File { + val relativePath = File(project.projectDir, "$name.iml").toRelativeString(project.rootProject.projectDir) return File(project.rootProject.projectDir, ".idea/modules/$relativePath") } - for ((nameSuffix, roots) in mapOf(".src" to productionContentRoots, ".test" to testContentRoots)) { - if (roots.isEmpty()) { + val sourceSets = parseSourceSets(project).sortedBy { it.forTests } + for (sourceSet in sourceSets) { + val sourceRoots = mutableListOf() + + for (dir in sourceSet.sourceDirectories) { + sourceRoots += PSourceRoot(dir, if (sourceSet.forTests) Kind.TEST else Kind.PRODUCTION) + } + + for (dir in sourceSet.resourceDirectories) { + sourceRoots += PSourceRoot(dir, if (sourceSet.forTests) Kind.TEST_RESOURCES else Kind.RESOURCES) + } + + if (sourceRoots.isEmpty()) { continue } - val mainRoot = roots.first() + val productionModule = if (sourceSet.forTests) modules.firstOrNull { !it.forTests } else null - var dependencies = parseDependencies(project, mainRoot.forTests) - if (productionContentRoots.isNotEmpty() && mainRoot.forTests) { - val productionModuleDependency = PDependency.Module(project.pillModuleName + ".src") - dependencies += POrderRoot(productionModuleDependency, Scope.COMPILE, true) + val contentRoots = sourceRoots.map { PContentRoot(it.directory, listOf(it), emptyList()) } + + var orderRoots = parseDependencies(project, sourceSet) + if (productionModule != null) { + val productionModuleDependency = PDependency.Module(productionModule.name) + orderRoots = listOf(POrderRoot(productionModuleDependency, Scope.COMPILE, true)) + orderRoots } - val module = PModule( - project.pillModuleName + nameSuffix, - mainRoot.path, - getModuleFile(nameSuffix), - roots, - dependencies, - productionSourcesModule + val name = project.pillModuleName + "." + sourceSet.name + + modules += PModule( + name = name, + path = makePath(project, sourceSet.name), + forTests = sourceSet.forTests, + rootDirectory = sourceRoots.first().directory, + moduleFile = getModuleFile(name), + contentRoots = contentRoots, + orderRoots = orderRoots, + kotlinOptions = sourceSet.kotlinOptions, + moduleForProductionSources = productionModule ) - - modules += module - - if (!mainRoot.forTests) { - productionSourcesModule = module - } } val mainModuleFileRelativePath = when (project) { project.rootProject -> File(project.rootProject.projectDir, project.rootProject.name + ".iml") - else -> getModuleFile() + else -> getModuleFile(project.pillModuleName) } modules += PModule( - project.pillModuleName, - project.projectDir, - mainModuleFileRelativePath, - listOf(PContentRoot(project.projectDir, false, emptyList(), allExcludedDirs)), - if (modules.isEmpty()) parseDependencies(project, false) else emptyList() + name = project.pillModuleName, + path = project.path, + forTests = false, + rootDirectory = project.projectDir, + moduleFile = mainModuleFileRelativePath, + contentRoots = listOf(PContentRoot(project.projectDir, listOf(), getExcludedDirs(project, excludedProjects))), + orderRoots = emptyList(), + kotlinOptions = null, + moduleForProductionSources = null ) return modules } -private fun parseContentRoots(project: Project): List { - val sourceRoots = parseSourceRoots(project).groupBy { it.kind } - fun getRoots(kind: PSourceRoot.Kind) = sourceRoots[kind] ?: emptyList() +private fun getExcludedDirs(project: Project, excludedProjects: List): List { + fun getJavaExcludedDirs() = project.plugins.findPlugin(IdeaPlugin::class.java) + ?.model?.module?.excludeDirs?.toList() ?: emptyList() - val productionSourceRoots = getRoots(Kind.PRODUCTION) + getRoots(Kind.RESOURCES) - val testSourceRoots = getRoots(Kind.TEST) + getRoots(Kind.TEST_RESOURCES) + fun getPillExcludedDirs() = project.extensions.getByType(PillExtension::class.java).excludedDirs - fun createContentRoots(sourceRoots: List, forTests: Boolean): List { - return sourceRoots.map { PContentRoot(it.path, forTests, listOf(it), emptyList()) } - } - - return createContentRoots(productionSourceRoots, forTests = false) + - createContentRoots(testSourceRoots, forTests = true) + return getPillExcludedDirs() + getJavaExcludedDirs() + project.buildDir + + (if (project == project.rootProject) excludedProjects.map { it.buildDir } else emptyList()) } -private fun parseSourceRoots(project: Project): List { +private fun parseSourceSets(project: Project): List { if (!project.plugins.hasPlugin(JavaPlugin::class.java)) { return emptyList() } val kotlinTasksBySourceSet = project.tasks.names - .filter { it.startsWith("compile") && it.endsWith("Kotlin") } - .map { project.tasks.getByName(it) } - .associateBy { it.invokeInternal("getSourceSetName") } + .filter { it.startsWith("compile") && it.endsWith("Kotlin") } + .map { project.tasks.getByName(it) } + .associateBy { it.invokeInternal("getSourceSetName") } - val sourceRoots = mutableListOf() + val gradleSourceSets = project.sourceSets?.toList() ?: emptyList() + val sourceSets = mutableListOf() - val sourceSets = project.sourceSets - if (sourceSets != null) { - for (sourceSet in sourceSets) { - val kotlinCompileTask = kotlinTasksBySourceSet[sourceSet.name] - val kind = if (sourceSet.isTestSourceSet) Kind.TEST else Kind.PRODUCTION + for (sourceSet in gradleSourceSets) { + val kotlinCompileTask = kotlinTasksBySourceSet[sourceSet.name] - fun Any.getKotlin(): SourceDirectorySet { - val kotlinMethod = javaClass.getMethod("getKotlin") - val oldIsAccessible = kotlinMethod.isAccessible - try { - kotlinMethod.isAccessible = true - return kotlinMethod(this) as SourceDirectorySet - } finally { - kotlinMethod.isAccessible = oldIsAccessible - } - } - - val kotlinSourceDirectories = (sourceSet as HasConvention).convention - .plugins["kotlin"]?.getKotlin()?.srcDirs - ?: emptySet() - - val directories = (sourceSet.java.sourceDirectories.files + kotlinSourceDirectories).toList() - .filter { it.exists() } - .takeIf { it.isNotEmpty() } - ?: continue - - val kotlinOptions = kotlinCompileTask?.let { getKotlinOptions(it) } - - for (resourceRoot in sourceSet.resources.sourceDirectories.files) { - if (!resourceRoot.exists() || resourceRoot in directories) { - continue - } - - val resourceRootKind = when (kind) { - Kind.PRODUCTION -> Kind.RESOURCES - Kind.TEST -> Kind.TEST_RESOURCES - else -> error("Invalid source root kind $kind") - } - - sourceRoots += PSourceRoot(resourceRoot, resourceRootKind, kotlinOptions) - } - - for (directory in directories) { - sourceRoots += PSourceRoot(directory, kind, kotlinOptions) - } - - for (root in parseResourceRootsProcessedByProcessResourcesTask(project, sourceSet)) { - if (sourceRoots.none { it.path == root.path }) { - sourceRoots += root - } - } + fun Any.getKotlin(): SourceDirectorySet { + val kotlinMethod = javaClass.getMethod("getKotlin") + kotlinMethod.isAccessible = true + return kotlinMethod(this) as SourceDirectorySet } + + val kotlinSourceDirectories = (sourceSet as HasConvention).convention + .plugins["kotlin"]?.getKotlin()?.srcDirs ?: emptySet() + + val sourceDirectories = (sourceSet.java.sourceDirectories.files + kotlinSourceDirectories).toList() + + val resourceDirectoriesFromSourceSet = sourceSet.resources.sourceDirectories.files + val resourceDirectoriesFromTask = parseResourceRootsProcessedByProcessResourcesTask(project, sourceSet) + + val resourceDirectories = (resourceDirectoriesFromSourceSet + resourceDirectoriesFromTask) + .distinct().filter { it !in sourceDirectories } + + sourceSets += PSourceSet( + name = sourceSet.name, + forTests = sourceSet.isTestSourceSet, + sourceDirectories = sourceDirectories, + resourceDirectories = resourceDirectories, + kotlinOptions = kotlinCompileTask?.let { getKotlinOptions(it) }, + compileClasspathConfigurationName = sourceSet.compileClasspathConfigurationName, + runtimeClasspathConfigurationName = sourceSet.runtimeClasspathConfigurationName + ) } - return sourceRoots + return sourceSets } -private fun parseResourceRootsProcessedByProcessResourcesTask(project: Project, sourceSet: SourceSet): List { +private fun parseResourceRootsProcessedByProcessResourcesTask(project: Project, sourceSet: SourceSet): List { val isMainSourceSet = sourceSet.name == SourceSet.MAIN_SOURCE_SET_NAME - val resourceRootKind = if (sourceSet.isTestSourceSet) PSourceRoot.Kind.TEST_RESOURCES else PSourceRoot.Kind.RESOURCES val taskNameBase = "processResources" val taskName = if (isMainSourceSet) taskNameBase else sourceSet.name + taskNameBase.capitalize() val task = project.tasks.findByName(taskName) as? ProcessResources ?: return emptyList() @@ -309,8 +328,7 @@ private fun parseResourceRootsProcessedByProcessResourcesTask(project: Project, spec.children.forEach(::collectRoots) } collectRoots(task.rootSpec) - - return roots.map { PSourceRoot(it, resourceRootKind, null) } + return roots } private val SourceSet.isTestSourceSet: Boolean @@ -322,92 +340,58 @@ private fun getKotlinOptions(kotlinCompileTask: Any): PSourceRootKotlinOptions? val compileArguments = run { val method = kotlinCompileTask::class.java.getMethod("getSerializedCompilerArguments") method.isAccessible = true + @Suppress("UNCHECKED_CAST") method.invoke(kotlinCompileTask) as List } fun parseBoolean(name: String) = compileArguments.contains("-$name") fun parseString(name: String) = compileArguments.dropWhile { it != "-$name" }.drop(1).firstOrNull() - fun isOptionForScriptingCompilerPlugin(option: String) - = option.startsWith("-Xplugin=") && option.contains("kotlin-scripting-compiler") + fun isOptionForScriptingCompilerPlugin(option: String): Boolean { + return option.startsWith("-Xplugin=") && option.contains("kotlin-scripting-compiler") + } val extraArguments = compileArguments.filter { it.startsWith("-X") && !isOptionForScriptingCompilerPlugin(it) } return PSourceRootKotlinOptions( - parseBoolean("no-stdlib"), - parseBoolean("no-reflect"), - parseString("module-name"), - parseString("api-version"), - parseString("language-version"), - parseString("jvm-target"), - extraArguments + parseBoolean("no-stdlib"), + parseBoolean("no-reflect"), + parseString("module-name"), + parseString("api-version"), + parseString("language-version"), + parseString("jvm-target"), + extraArguments ) } private fun Any.invokeInternal(name: String, instance: Any = this): Any? { val method = javaClass.methods.single { it.name.startsWith(name) && it.parameterTypes.isEmpty() } - - val oldIsAccessible = method.isAccessible - try { - method.isAccessible = true - return method.invoke(instance) - } finally { - method.isAccessible = oldIsAccessible - } + method.isAccessible = true + return method.invoke(instance) } -private fun ParserContext.parseDependencies(project: Project, forTests: Boolean): List { - val configurations = project.configurations - val configurationMapping = if (forTests) TEST_CONFIGURATION_MAPPING else CONFIGURATION_MAPPING +private fun parseDependencies(project: Project, sourceSet: PSourceSet): List { + val roots = mutableListOf() - val mainRoots = mutableListOf() - val deferredRoots = mutableListOf() - - for ((configurationNames, scope) in configurationMapping) { - for (configurationName in configurationNames) { - val configuration = configurations.findByName(configurationName) ?: continue - val (main, deferred) = project.resolveDependencies(configuration, forTests, dependencyMappers) - mainRoots += main.map { POrderRoot(it, scope) } - deferredRoots += deferred.map { POrderRoot(it, scope) } + fun process(name: String, scope: Scope) { + val configuration = project.configurations.findByName(name) ?: return + for (file in configuration.resolve()) { + val library = PLibrary(file.name, listOf(file)) + val dependency = PDependency.ModuleLibrary(library) + roots += POrderRoot(dependency, scope) } } - return removeDuplicates(mainRoots + deferredRoots) -} + process(sourceSet.compileClasspathConfigurationName, Scope.PROVIDED) + process(sourceSet.runtimeClasspathConfigurationName, Scope.RUNTIME) -fun removeDuplicates(roots: List): List { - val dependenciesByScope = roots.groupBy { it.scope }.mapValues { it.value.mapTo(mutableSetOf()) { it.dependency } } - fun dependenciesFor(scope: Scope) = dependenciesByScope[scope] ?: emptySet() - - val result = mutableSetOf() - for (root in roots.distinct()) { - val scope = root.scope - val dependency = root.dependency - - if (root in result) { - continue - } - - if ((scope == Scope.PROVIDED || scope == Scope.RUNTIME) && dependency in dependenciesFor(Scope.COMPILE)) { - continue - } - - if (scope == Scope.PROVIDED && dependency in dependenciesFor(Scope.RUNTIME)) { - result += POrderRoot(dependency, Scope.COMPILE) - continue - } - - if (scope == Scope.RUNTIME && dependency in dependenciesFor(Scope.PROVIDED)) { - result += POrderRoot(dependency, Scope.COMPILE) - continue - } - - result += root + if (sourceSet.forTests) { + process("jpsTest", Scope.TEST) } - return result.toList() + return roots } val Project.pillModuleName: String diff --git a/buildSrc/src/main/kotlin/pill/pathContext.kt b/buildSrc/src/main/kotlin/pill/pathContext.kt index 93661c47a83..2d889723375 100644 --- a/buildSrc/src/main/kotlin/pill/pathContext.kt +++ b/buildSrc/src/main/kotlin/pill/pathContext.kt @@ -1,3 +1,8 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + @file:Suppress("PackageDirectoryMismatch") package org.jetbrains.kotlin.pill @@ -50,5 +55,4 @@ class ModuleContext(val project: PProject, val module: PModule) : PathContext { } } -fun String.withSlash() = if (this.endsWith("/")) this else (this + "/") -fun String.withoutSlash() = this.trimEnd('/') \ No newline at end of file +fun String.withSlash() = if (this.endsWith("/")) this else ("$this/") \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/pill/plugin.kt b/buildSrc/src/main/kotlin/pill/plugin.kt index 52f2f6c7c52..e41faf475e0 100644 --- a/buildSrc/src/main/kotlin/pill/plugin.kt +++ b/buildSrc/src/main/kotlin/pill/plugin.kt @@ -1,3 +1,8 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + @file:Suppress("PackageDirectoryMismatch") package org.jetbrains.kotlin.pill @@ -10,71 +15,50 @@ import shadow.org.jdom2.* import shadow.org.jdom2.output.Format import shadow.org.jdom2.output.XMLOutputter import java.io.File - -class PillConfigurablePlugin : Plugin { - override fun apply(project: Project) { - project.configurations.maybeCreate(EmbeddedComponents.CONFIGURATION_NAME) - project.extensions.create("pill", PillExtension::class.java) - } -} +import java.util.* +import kotlin.collections.HashMap class JpsCompatiblePlugin : Plugin { companion object { - private fun getDependencyMappers(projectLibraries: List): List { - val mappersForKotlinLibrariesExeptStdlib = projectLibraries - .filter { it.name != "kotlin-stdlib" } - .map { DependencyMapper.forProject(it.originalName) { MappedDependency(PDependency.Library(it.name)) } } + private val DIST_LIBRARIES = listOf( + ":kotlin-annotations-jvm", + ":kotlin-stdlib", + ":kotlin-stdlib-jdk7", + ":kotlin-stdlib-jdk8", + ":kotlin-reflect", + ":kotlin-test:kotlin-test-jvm", + ":kotlin-test:kotlin-test-junit", + ":kotlin-script-runtime", + ":kotlin-serialization" + ) - val disabledModuleMappers = listOf( - ":kotlin-stdlib-common", - ":core:builtins", - ":kotlin-compiler", - ":kotlin-compiler-embeddable", - ":kotlin-test:kotlin-test-common", - ":kotlin-test:kotlin-test-annotations-common" - ).map { DependencyMapper.forProject(it) { null } } + private val IGNORED_LIBRARIES = listOf( + // Libraries + ":kotlin-stdlib-common", + ":kotlin-reflect-api", + ":kotlin-test:kotlin-test-common", + ":kotlin-test:kotlin-test-annotations-common", + // Other + ":kotlin-compiler", + ":kotlin-daemon-embeddable", + ":kotlin-compiler-embeddable", + ":kotlin-android-extensions", + ":kotlin-scripting-compiler-embeddable", + ":kotlin-scripting-compiler-impl-embeddable", + ":kotlin-scripting-jvm-host-embeddable" + ) - return listOf( - DependencyMapper.forProject(":kotlin-stdlib") { - MappedDependency( - PDependency.Library("kotlin-stdlib"), - listOf(PDependency.Library("annotations-13.0")) - ) - }, - DependencyMapper.forProject(":kotlin-test:kotlin-test-jvm") { MappedDependency(PDependency.Library("kotlin-test-jvm")) }, - DependencyMapper.forProject(":kotlin-reflect-api") { MappedDependency(PDependency.Library("kotlin-reflect")) } - ) + mappersForKotlinLibrariesExeptStdlib + disabledModuleMappers - } + private val MAPPED_LIBRARIES = mapOf( + ":kotlin-reflect-api/java9" to ":kotlin-reflect/main" + ) - fun getProjectLibraries(rootProject: Project): List { - val distLibDir = File(rootProject.extra["distLibDir"].toString()) - fun distJar(name: String) = File(rootProject.projectDir, "dist/kotlinc/lib/$name.jar") - - val libraries = rootProject.allprojects - .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(), - originalName = library.path - ) - } - - return libraries + PLibrary("annotations-13.0", classes = listOf(distJar("annotations-13.0"))) - } + private val LIB_DIRECTORIES = listOf("dependencies", "dist") } override fun apply(project: Project) { - project.plugins.apply(PillConfigurablePlugin::class.java) + project.configurations.maybeCreate(EmbeddedComponents.CONFIGURATION_NAME) + project.extensions.create("pill", PillExtension::class.java) + // 'jpsTest' does not require the 'tests-jar' artifact project.configurations.create("jpsTest") @@ -129,13 +113,14 @@ class JpsCompatiblePlugin : Plugin { return } - val projectLibraries = getProjectLibraries(rootProject) - val dependencyMappers = getDependencyMappers(projectLibraries) + val parserContext = ParserContext(variant) - val parserContext = ParserContext(dependencyMappers, variant) + val dependencyPatcher = DependencyPatcher(rootProject) + val dependencyMappers = listOf(dependencyPatcher, ::attachPlatformSources, ::attachAsmSources) - val jpsProject = parse(rootProject, projectLibraries, parserContext) - .mapLibraries(this::attachPlatformSources, this::attachAsmSources) + val jpsProject = parse(rootProject, parserContext) + .mapDependencies(dependencyMappers) + .copy(libraries = dependencyPatcher.libraries) val files = render(jpsProject) @@ -143,7 +128,13 @@ class JpsCompatiblePlugin : Plugin { removeJpsAndPillRunConfigurations() removeAllArtifactConfigurations() - generateKotlinPluginArtifactFile(rootProject, dependencyMappers).write() + val artifactDependencyMapper = object : OpaqueDependencyMapper { + override fun map(dependency: PDependency): List { + return jpsProject.mapDependency(dependency, dependencyMappers) + } + } + + generateKotlinPluginArtifactFile(rootProject, artifactDependencyMapper).write() copyRunConfigurations() setOptionsForDefaultJunitRunConfiguration(rootProject) @@ -192,7 +183,7 @@ class JpsCompatiblePlugin : Plugin { .replace("\$ADDITIONAL_IDEA_ARGS\$", additionalIdeaArgs) } - runConfigurationsDir.listFiles() + (runConfigurationsDir.listFiles() ?: emptyArray()) .filter { it.extension == "xml" } .map { it.name to substitute(it.readText()) } .forEach { File(targetDir, it.first).writeText(it.second) } @@ -260,11 +251,11 @@ class JpsCompatiblePlugin : Plugin { } if (options.none { it == "-ea" }) { - options += "-ea" + options = options + "-ea" } addOrReplaceOptionValue("idea.home.path", platformDirProjectRelative) - addOrReplaceOptionValue("ideaSdk.androidPlugin.path", platformDirProjectRelative + "/plugins/android/lib") + addOrReplaceOptionValue("ideaSdk.androidPlugin.path", "$platformDirProjectRelative/plugins/android/lib") addOrReplaceOptionValue("use.jps", "true") addOrReplaceOptionValue("kotlinVersion", project.rootProject.extra["kotlinVersion"].toString()) @@ -287,8 +278,9 @@ class JpsCompatiblePlugin : Plugin { kotlinJunitConfiguration.applyJUnitTemplate() val output = XMLOutputter().also { + @Suppress("UsePropertyAccessSyntax") it.format = Format.getPrettyFormat().apply { - setEscapeStrategy { Verifier.isHighSurrogate(it) || it == '"' } + setEscapeStrategy { c -> Verifier.isHighSurrogate(c) || c == '"' } setIndent(" ") setTextMode(Format.TextMode.TRIM) setOmitEncoding(false) @@ -304,40 +296,138 @@ class JpsCompatiblePlugin : Plugin { workspaceFile.writeText(postProcessedXml) } - private fun attachPlatformSources(library: PLibrary): PLibrary { - val platformSourcesJar = File(platformDir, "../../../sources/intellij-$platformVersion-sources.jar") + private class DependencyPatcher(private val rootProject: Project): Function2> { + private val mappings: Map> = run { + val distLibDir = File(rootProject.extra["distLibDir"].toString()) + val result = HashMap>() - if (library.classes.any { it.startsWith(platformDir) || it.startsWith(intellijCoreDir) }) { - return library.attachSource(platformSourcesJar) - } + fun List.filterExisting() = filter { it.exists() } - return library - } - - private fun attachAsmSources(library: PLibrary): PLibrary { - val asmSourcesJar = File(platformDir, "../asm-shaded-sources/asm-src-$platformBaseNumber.jar") - val asmAllJar = File(platformDir, "lib/asm-all.jar") - - if (library.classes.any { it == asmAllJar }) { - return library.attachSource(asmSourcesJar) - } - - return library - } - - private fun PProject.mapLibraries(vararg mappers: (PLibrary) -> PLibrary): PProject { - fun mapLibrary(root: POrderRoot): POrderRoot { - val dependency = root.dependency - - if (dependency is PDependency.ModuleLibrary) { - val newLibrary = mappers.fold(dependency.library) { lib, mapper -> mapper(lib) } - return root.copy(dependency = dependency.copy(library = newLibrary)) + for (path in DIST_LIBRARIES) { + val project = rootProject.findProject(path) ?: error("Project not found") + val archiveName = project.convention.findPlugin(BasePluginConvention::class.java)!!.archivesBaseName + val classesJars = listOf(File(distLibDir, "$archiveName.jar")).filterExisting() + val sourcesJars = listOf(File(distLibDir, "$archiveName-sources.jar")).filterExisting() + result["$path/main"] = Optional.of(PLibrary(archiveName, classesJars, sourcesJars, originalName = path)) } - return root + for (path in IGNORED_LIBRARIES) { + result["$path/main"] = Optional.empty() + } + + for ((old, new) in MAPPED_LIBRARIES) { + result[old] = result[new] ?: error("Mapped library $old -> $new not found") + } + + return@run result + } + + val libraries: List = mappings.values.filter { it.isPresent }.map { it.get() } + + override fun invoke(project: PProject, dependency: PDependency): List { + if (dependency !is PDependency.ModuleLibrary) { + return listOf(dependency) + } + + val root = dependency.library.classes.singleOrNull() ?: return listOf(dependency) + val paths = project.artifacts[root.absolutePath] + + if (paths == null) { + val projectDir = rootProject.projectDir + if (projectDir.isParent(root) && LIB_DIRECTORIES.none { File(projectDir, it).isParent(root) }) { + rootProject.logger.warn("Paths not found for root: ${root.absolutePath}") + return emptyList() + } + return listOf(dependency) + } + + val result = mutableListOf() + for (path in paths) { + val module = project.modules.find { it.path == path } + if (module != null) { + result += PDependency.Module(module.name) + continue + } + + val maybeLibrary = mappings[path] + if (maybeLibrary == null) { + rootProject.logger.warn("Library not found for root: ${root.absolutePath} ($path)") + continue + } + + if (maybeLibrary.isPresent) { + result += PDependency.Library(maybeLibrary.get().name) + } + } + + return result + } + + private fun File.isParent(child: File): Boolean { + var parent = child.parentFile ?: return false + while (true) { + if (parent == this) { + return true + } + parent = parent.parentFile ?: return false + } + } + } + + private fun attachPlatformSources(@Suppress("UNUSED_PARAMETER") project: PProject, dependency: PDependency): List { + if (dependency is PDependency.ModuleLibrary) { + val library = dependency.library + val platformSourcesJar = File(platformDir, "../../../sources/intellij-$platformVersion-sources.jar") + + if (library.classes.any { it.startsWith(platformDir) || it.startsWith(intellijCoreDir) }) { + return listOf(dependency.copy(library = library.attachSource(platformSourcesJar))) + } + } + + return listOf(dependency) + } + + private fun attachAsmSources(@Suppress("UNUSED_PARAMETER") project: PProject, dependency: PDependency): List { + if (dependency is PDependency.ModuleLibrary) { + val library = dependency.library + val asmSourcesJar = File(platformDir, "../asm-shaded-sources/asm-src-$platformBaseNumber.jar") + val asmAllJar = File(platformDir, "lib/asm-all.jar") + + if (library.classes.any { it == asmAllJar }) { + return listOf(dependency.copy(library = library.attachSource(asmSourcesJar))) + } + } + + return listOf(dependency) + } + + private fun PProject.mapDependencies(mappers: List<(PProject, PDependency) -> List>): PProject { + fun mapRoot(root: POrderRoot): List { + val dependencies = mapDependency(root.dependency, mappers) + return dependencies.map { root.copy(dependency = it) } + } + + val modules = this.modules.map { module -> + val newOrderRoots = module.orderRoots.flatMap(::mapRoot).distinct() + module.copy(orderRoots = newOrderRoots) } - val modules = this.modules.map { it.copy(orderRoots = it.orderRoots.map(::mapLibrary)) } return this.copy(modules = modules) } + + private fun PProject.mapDependency( + dependency: PDependency, + mappers: List<(PProject, PDependency) -> List> + ): List { + var dependencies = listOf(dependency) + for (mapper in mappers) { + val newDependencies = mutableListOf() + for (dep in dependencies) { + newDependencies += mapper(this, dep) + } + dependencies = newDependencies + } + + return dependencies + } } \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/pill/render.kt b/buildSrc/src/main/kotlin/pill/render.kt index 206130caf52..54c5aa5fcc6 100644 --- a/buildSrc/src/main/kotlin/pill/render.kt +++ b/buildSrc/src/main/kotlin/pill/render.kt @@ -1,4 +1,9 @@ -@file:Suppress("PackageDirectoryMismatch") +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +@file:Suppress("PackageDirectoryMismatch", "FunctionName") package org.jetbrains.kotlin.pill import java.io.File @@ -49,12 +54,7 @@ private fun renderModule(project: PProject, module: PModule) = PFile( xml("component", "name" to "TestModuleProperties", "production-module" to moduleForProductionSources.name) } - val kotlinCompileOptionsList = module.contentRoots.flatMap { it.sourceRoots }.mapNotNull { it.kotlinOptions } - var kotlinCompileOptions = kotlinCompileOptionsList.firstOrNull() - for (otherOptions in kotlinCompileOptionsList.drop(1)) { - kotlinCompileOptions = kotlinCompileOptions?.intersect(otherOptions) - } - + val kotlinCompileOptions = module.kotlinOptions val pathContext = ModuleContext(project, module) val platformVersion = (kotlinCompileOptions?.jvmTarget ?: "1.8") @@ -100,10 +100,10 @@ private fun renderModule(project: PProject, module: PModule) = PFile( ) { xml("exclude-output") - for (contentRoot in module.contentRoots) { + for (contentRoot in module.contentRoots.filter { it.path.exists() }) { xml("content", pathContext.url(contentRoot.path)) { for (sourceRoot in contentRoot.sourceRoots) { - var args = arrayOf(pathContext.url(sourceRoot.path)) + var args = arrayOf(pathContext.url(sourceRoot.directory)) args += when (sourceRoot.kind) { PSourceRoot.Kind.PRODUCTION -> ("isTestSource" to "false") diff --git a/buildSrc/src/main/kotlin/pill/xml.kt b/buildSrc/src/main/kotlin/pill/xml.kt index 71fe9504348..ab0b04c5605 100644 --- a/buildSrc/src/main/kotlin/pill/xml.kt +++ b/buildSrc/src/main/kotlin/pill/xml.kt @@ -1,4 +1,9 @@ -@file:Suppress("PackageDirectoryMismatch") +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +@file:Suppress("PackageDirectoryMismatch", "ClassName") package org.jetbrains.kotlin.pill import shadow.org.jdom2.Document diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/test/JUnit3RunnerWithInnersForJPS.java b/compiler/tests-common/tests/org/jetbrains/kotlin/test/JUnit3RunnerWithInnersForJPS.java index 13251ccb8ff..99db44b9178 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/test/JUnit3RunnerWithInnersForJPS.java +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/test/JUnit3RunnerWithInnersForJPS.java @@ -90,7 +90,7 @@ public class JUnit3RunnerWithInnersForJPS extends Runner implements Filterable, String compilerXmlSourcePath = "compiler/cli/cli-common/resources/META-INF/extensions/compiler.xml"; String jpsTargetDirectory = "out/production/kotlin.idea.main"; - String pillTargetDirectory = "out/production/idea.src"; + String pillTargetDirectory = "out/production/idea.main"; String baseDir = Files.exists(Paths.get(jpsTargetDirectory)) ? jpsTargetDirectory : pillTargetDirectory; String compilerXmlTargetPath = baseDir + "/META-INF/extensions/compiler.xml"; diff --git a/libraries/kotlin.test/annotations-common/build.gradle b/libraries/kotlin.test/annotations-common/build.gradle index 199288a347c..50c7d403892 100644 --- a/libraries/kotlin.test/annotations-common/build.gradle +++ b/libraries/kotlin.test/annotations-common/build.gradle @@ -1,7 +1,6 @@ description = 'Kotlin Test Annotations Common' apply plugin: 'kotlin-platform-common' -apply plugin: 'pill-configurable' configurePublishing(project) @@ -10,10 +9,6 @@ dependencies { testCompile project(":kotlin-test:kotlin-test-common") } -pill { - importAsLibrary = true -} - tasks.withType(org.jetbrains.kotlin.gradle.dsl.KotlinCompile) { kotlinOptions.freeCompilerArgs += "-Xallow-kotlin-package" } diff --git a/libraries/kotlin.test/common/build.gradle b/libraries/kotlin.test/common/build.gradle index dc3e2e70773..6e3a9d47516 100644 --- a/libraries/kotlin.test/common/build.gradle +++ b/libraries/kotlin.test/common/build.gradle @@ -1,7 +1,6 @@ description = 'Kotlin Test Common' apply plugin: 'kotlin-platform-common' -apply plugin: 'pill-configurable' configurePublishing(project) @@ -10,10 +9,6 @@ dependencies { testCompile project(":kotlin-test:kotlin-test-annotations-common") } -pill { - importAsLibrary = true -} - jar { manifestAttributes(manifest, project, 'Test') } diff --git a/libraries/kotlin.test/junit/build.gradle b/libraries/kotlin.test/junit/build.gradle index a5e05e75135..1d2bb4e72fc 100644 --- a/libraries/kotlin.test/junit/build.gradle +++ b/libraries/kotlin.test/junit/build.gradle @@ -1,15 +1,10 @@ description = 'Kotlin Test JUnit' apply plugin: 'kotlin-platform-jvm' -apply plugin: 'pill-configurable' configureJvm6Project(project) configurePublishing(project) -pill { - importAsLibrary = true -} - dependencies { expectedBy project(':kotlin-test:kotlin-test-annotations-common') compile project(':kotlin-test:kotlin-test-jvm') diff --git a/libraries/kotlin.test/jvm/build.gradle b/libraries/kotlin.test/jvm/build.gradle index 37cf59d635c..7d773a2a67e 100644 --- a/libraries/kotlin.test/jvm/build.gradle +++ b/libraries/kotlin.test/jvm/build.gradle @@ -1,15 +1,10 @@ description = 'Kotlin Test' apply plugin: 'kotlin-platform-jvm' -apply plugin: 'pill-configurable' configureJvm6Project(project) configurePublishing(project) -pill { - importAsLibrary = true -} - def includeJava9 = BuildPropertiesKt.getKotlinBuildProperties(project).includeJava9 sourceSets { diff --git a/libraries/reflect/build.gradle.kts b/libraries/reflect/build.gradle.kts index 3fae07e42eb..97adf45f214 100644 --- a/libraries/reflect/build.gradle.kts +++ b/libraries/reflect/build.gradle.kts @@ -19,17 +19,12 @@ buildscript { plugins { java - id("pill-configurable") } callGroovy("configureJavaOnlyJvm6Project", project) publish() -pill { - importAsLibrary = true -} - val core = "$rootDir/core" val relocatedCoreSrc = "$buildDir/core-relocated" val libsDir = property("libsDir") diff --git a/libraries/stdlib/common/build.gradle b/libraries/stdlib/common/build.gradle index 4e00b3f4b49..04aadd5d2dc 100644 --- a/libraries/stdlib/common/build.gradle +++ b/libraries/stdlib/common/build.gradle @@ -1,17 +1,12 @@ description = 'Kotlin Common Standard Library' apply plugin: 'kotlin-platform-common' -apply plugin: 'pill-configurable' configurePublishing(project) def commonSrcDir = "../src" def commonTestSrcDir = "../test" -pill { - importAsLibrary = true -} - sourceSets { main { kotlin { diff --git a/libraries/stdlib/jdk7/build.gradle b/libraries/stdlib/jdk7/build.gradle index dfab83ca600..f64cf54e52e 100644 --- a/libraries/stdlib/jdk7/build.gradle +++ b/libraries/stdlib/jdk7/build.gradle @@ -1,16 +1,11 @@ description = 'Kotlin Standard Library JDK 7 extension' apply plugin: 'kotlin' -apply plugin: 'pill-configurable' configureJvm6Project(project) configurePublishing(project) ext.javaHome = JDK_17 -pill { - importAsLibrary = true -} - sourceSets { main { kotlin { diff --git a/libraries/stdlib/jdk8/build.gradle b/libraries/stdlib/jdk8/build.gradle index 8ac6cc1bf4a..8ef44ede43d 100644 --- a/libraries/stdlib/jdk8/build.gradle +++ b/libraries/stdlib/jdk8/build.gradle @@ -1,17 +1,12 @@ description = 'Kotlin Standard Library JDK 8 extension' apply plugin: 'kotlin' -apply plugin: 'pill-configurable' configureJvm6Project(project) configurePublishing(project) ext.javaHome = JDK_18 ext.jvmTarget = "1.8" -pill { - importAsLibrary = true -} - dependencies { compile project(':kotlin-stdlib') compile project(':kotlin-stdlib-jdk7') diff --git a/libraries/stdlib/jvm/build.gradle b/libraries/stdlib/jvm/build.gradle index 687a280b026..d4f746dfa36 100644 --- a/libraries/stdlib/jvm/build.gradle +++ b/libraries/stdlib/jvm/build.gradle @@ -1,7 +1,6 @@ description = 'Kotlin Standard Library for JVM' apply plugin: 'kotlin-platform-jvm' -apply plugin: 'pill-configurable' archivesBaseName = 'kotlin-stdlib' @@ -12,10 +11,6 @@ configurations { distSources } -pill { - importAsLibrary = true -} - sourceSets { main { java { diff --git a/libraries/tools/kotlin-annotations-jvm/build.gradle b/libraries/tools/kotlin-annotations-jvm/build.gradle index 985812ad266..f12afdc894f 100644 --- a/libraries/tools/kotlin-annotations-jvm/build.gradle +++ b/libraries/tools/kotlin-annotations-jvm/build.gradle @@ -1,15 +1,10 @@ description = 'Kotlin annotations for JVM' apply plugin: 'kotlin' -apply plugin: 'pill-configurable' configureJvm6Project(project) configurePublishing(project) -pill { - importAsLibrary = true -} - sourceSets { main { java { diff --git a/libraries/tools/kotlin-gradle-statistics/build.gradle.kts b/libraries/tools/kotlin-gradle-statistics/build.gradle.kts index 45608643fba..87462cdb2da 100644 --- a/libraries/tools/kotlin-gradle-statistics/build.gradle.kts +++ b/libraries/tools/kotlin-gradle-statistics/build.gradle.kts @@ -2,6 +2,7 @@ description = "kotlin-gradle-statistics" plugins { kotlin("jvm") + id("jps-compatible") } dependencies { diff --git a/libraries/tools/script-runtime/build.gradle b/libraries/tools/script-runtime/build.gradle index b3951d4617d..553137d2498 100644 --- a/libraries/tools/script-runtime/build.gradle +++ b/libraries/tools/script-runtime/build.gradle @@ -1,15 +1,10 @@ description 'Kotlin Script Runtime' apply plugin: 'kotlin' -apply plugin: 'pill-configurable' configureJvm6Project(project) configurePublishing(project) -pill { - importAsLibrary = true -} - dependencies { compileOnly kotlinStdlib() } diff --git a/prepare/jps-plugin/build.gradle.kts b/prepare/jps-plugin/build.gradle.kts index e8148a5fa6a..47b33ed941a 100644 --- a/prepare/jps-plugin/build.gradle.kts +++ b/prepare/jps-plugin/build.gradle.kts @@ -2,7 +2,6 @@ description = "Kotlin JPS plugin" plugins { java - id("pill-configurable") } val projectsToShadow = listOf(