mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-03-10 08:31:29 +00:00
Pill: Import KotlinPlugin artifact
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -29,6 +29,7 @@ build/
|
||||
!**/testData/**/*.iml
|
||||
.idea/libraries/Gradle*.xml
|
||||
.idea/libraries/Maven*.xml
|
||||
.idea/artifacts
|
||||
.idea/modules
|
||||
.idea/runConfigurations/JPS_*.xml
|
||||
.idea/libraries
|
||||
|
||||
183
buildSrc/src/main/kotlin/pill/kotlinPluginArtifact.kt
Normal file
183
buildSrc/src/main/kotlin/pill/kotlinPluginArtifact.kt
Normal file
@@ -0,0 +1,183 @@
|
||||
@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.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) {
|
||||
fun render(context: PathContext) = xml("component", "name" to "ArtifactManager") {
|
||||
xml("artifact", "name" to artifactName) {
|
||||
xml("output-path") {
|
||||
raw(context(outputDir))
|
||||
}
|
||||
|
||||
add(contents.renderRecursively(context))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class ArtifactElement {
|
||||
private val myChildren = mutableListOf<ArtifactElement>()
|
||||
val children get() = myChildren
|
||||
|
||||
fun add(child: ArtifactElement) {
|
||||
myChildren += child
|
||||
}
|
||||
|
||||
abstract fun render(context: PathContext): xml
|
||||
|
||||
fun renderRecursively(context: PathContext): xml {
|
||||
return render(context).apply {
|
||||
children.forEach { add(it.renderRecursively(context)) }
|
||||
}
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
data class Directory(val name: String) : ArtifactElement() {
|
||||
override fun render(context: PathContext) = xml("element", "id" to "directory", "name" to name)
|
||||
}
|
||||
|
||||
data class Archive(val name: String) : ArtifactElement() {
|
||||
override fun render(context: PathContext) = xml("element", "id" to "archive", "name" to name)
|
||||
}
|
||||
|
||||
data class ModuleOutput(val moduleName: String) : ArtifactElement() {
|
||||
override fun render(context: PathContext) = xml("element", "id" to "module-output", "name" to moduleName)
|
||||
}
|
||||
|
||||
data class FileCopy(val source: File) : ArtifactElement() {
|
||||
override fun render(context: PathContext) = xml("element", "id" to "file-copy", "path" to context(source))
|
||||
}
|
||||
|
||||
data class DirectoryCopy(val source: File) : ArtifactElement() {
|
||||
override fun render(context: PathContext) = xml("element", "id" to "dir-copy", "path" to context(source))
|
||||
}
|
||||
|
||||
data class ProjectLibrary(val name: String) : ArtifactElement() {
|
||||
override fun render(context: PathContext) = xml("element", "id" to "library", "level" to "project", "name" to name)
|
||||
}
|
||||
|
||||
data class ExtractedDirectory(val archive: File, val pathInJar: String = "/") : ArtifactElement() {
|
||||
override fun render(context: PathContext) =
|
||||
xml("element", "id" to "extracted-dir", "path" to context(archive), "path-in-jar" to pathInJar)
|
||||
}
|
||||
}
|
||||
|
||||
fun generateKotlinPluginArtifactFile(rootProject: Project): PFile {
|
||||
val mainIdeaPluginTask = rootProject.tasks.getByName("ideaPlugin") as Copy
|
||||
val gradleArtifactDir = mainIdeaPluginTask.destinationDir
|
||||
|
||||
val ideaPluginTasks = mainIdeaPluginTask.taskDependencies
|
||||
.getDependencies(mainIdeaPluginTask)
|
||||
.filter { it.name == "ideaPlugin" }
|
||||
.filterIsInstance<Copy>()
|
||||
|
||||
val root = Root()
|
||||
|
||||
// Copy kotlinc directory
|
||||
root.add(DirectoryCopy(File(rootProject.extra["distKotlinHomeDir"].toString())))
|
||||
|
||||
for (task in ideaPluginTasks) {
|
||||
val spec = task.rootSpec.children.filterIsInstance<SingleParentCopySpec>().singleOrNull()
|
||||
?: error("Copy spec is not unique in ${rootProject.name}. Available specs: ${task.rootSpec.children}")
|
||||
|
||||
val sourcePaths = spec.sourcePaths
|
||||
for (sourcePath in sourcePaths) {
|
||||
if (sourcePath is ShadowJar) {
|
||||
if (sourcePath.project.path == ":prepare:idea-plugin") {
|
||||
val kotlinPluginJar = Archive(sourcePath.archiveName).also { root.getDirectory("lib").add(it) }
|
||||
|
||||
kotlinPluginJar.add(FileCopy(File(rootProject.projectDir, "resources/kotlinManifest.properties")))
|
||||
|
||||
for (jarFile in sourcePath.project.configurations.getByName("packedJars").resolve()) {
|
||||
kotlinPluginJar.add(ExtractedDirectory(jarFile))
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
for (projectPath in sourcePath.project.extra["projectsToShadow"] as List<String>) {
|
||||
val jpsModuleName = rootProject.findProject(projectPath)!!.name + ".src"
|
||||
kotlinPluginJar.add(ModuleOutput(jpsModuleName))
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
when (sourcePath) {
|
||||
is Jar -> {
|
||||
val targetDir = ("lib/" + task.destinationDir.toRelativeString(gradleArtifactDir)).withoutSlash()
|
||||
|
||||
val archiveForJar = Archive(sourcePath.project.name + ".jar").apply {
|
||||
if (task.project.plugins.hasPlugin(JavaPlugin::class.java)) {
|
||||
add(ModuleOutput(sourcePath.project.name + ".src"))
|
||||
}
|
||||
root.getDirectory(targetDir).add(this)
|
||||
}
|
||||
|
||||
val fatJarContentsConfiguration = sourcePath.project.configurations
|
||||
.findByName("fatJarContents")?.resolvedConfiguration
|
||||
|
||||
if (fatJarContentsConfiguration != null) {
|
||||
for ((_, _, dependency) in listOf(fatJarContentsConfiguration to Scope.COMPILE).collectDependencies()) {
|
||||
if (dependency.configuration == "runtimeElements") {
|
||||
archiveForJar.add(ModuleOutput(dependency.moduleName + ".src"))
|
||||
} else if (dependency.configuration == "tests-jar" || dependency.configuration == "jpsTest") {
|
||||
error("Test configurations are not allowed here")
|
||||
} else {
|
||||
for (file in dependency.moduleArtifacts.map { it.file }) {
|
||||
archiveForJar.add(ExtractedDirectory(file))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
is Configuration -> {
|
||||
require(sourcePath.name == "sideJars") { "Configurations other than 'sideJars' are not supported" }
|
||||
for (file in sourcePath.resolve()) {
|
||||
root.getDirectory("lib").add(FileCopy(file))
|
||||
}
|
||||
}
|
||||
else -> error("${task.name} Unexpected task type ${task.javaClass.name}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val artifact = PArtifact("KotlinPlugin", File(rootProject.projectDir, "out/artifacts/Kotlin"), root)
|
||||
return PFile(
|
||||
File(rootProject.projectDir, ".idea/artifacts/${artifact.artifactName}.xml"),
|
||||
artifact.render(ProjectContext(rootProject))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -345,9 +345,9 @@ private fun removeDuplicates(roots: List<POrderRoot>): List<POrderRoot> {
|
||||
return result.toList()
|
||||
}
|
||||
|
||||
private data class DependencyInfo(val configuration: ResolvedConfiguration, val scope: Scope, val dependency: ResolvedDependency)
|
||||
data class DependencyInfo(val configuration: ResolvedConfiguration, val scope: Scope, val dependency: ResolvedDependency)
|
||||
|
||||
private fun List<Pair<ResolvedConfiguration, Scope>>.collectDependencies(): List<DependencyInfo> {
|
||||
fun List<Pair<ResolvedConfiguration, Scope>>.collectDependencies(): List<DependencyInfo> {
|
||||
val dependencies = mutableListOf<DependencyInfo>()
|
||||
|
||||
val unprocessed = LinkedList<DependencyInfo>()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
@file:Suppress("PackageDirectoryMismatch")
|
||||
package org.jetbrains.kotlin.pill
|
||||
|
||||
import org.gradle.api.Project
|
||||
import java.io.File
|
||||
|
||||
interface PathContext {
|
||||
@@ -16,10 +17,12 @@ interface PathContext {
|
||||
}
|
||||
}
|
||||
|
||||
class ProjectContext(val project: PProject) : PathContext {
|
||||
class ProjectContext private constructor(val projectDir: File) : PathContext {
|
||||
constructor(project: PProject) : this(project.rootDirectory)
|
||||
constructor(project: Project) : this(project.projectDir)
|
||||
|
||||
override fun invoke(file: File): String {
|
||||
return file.absolutePath
|
||||
.replace(project.rootDirectory.absolutePath, "\$PROJECT_DIR\$")
|
||||
return file.absolutePath.replace(projectDir.absolutePath, "\$PROJECT_DIR\$")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,11 +32,12 @@ class ModuleContext(val project: PProject, val module: PModule) : PathContext {
|
||||
return file.absolutePath
|
||||
}
|
||||
|
||||
fun String.withSlash() = if (this.endsWith("/")) this else (this + "/")
|
||||
|
||||
return "\$MODULE_DIR\$/" +
|
||||
project.rootDirectory.toRelativeString(module.moduleFile.parentFile).withSlash() +
|
||||
module.rootDirectory.toRelativeString(project.rootDirectory).withSlash() +
|
||||
file.toRelativeString(module.rootDirectory)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun String.withSlash() = if (this.endsWith("/")) this else (this + "/")
|
||||
fun String.withoutSlash() = this.trimEnd('/')
|
||||
@@ -4,14 +4,9 @@ import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import shadow.org.jdom2.input.SAXBuilder
|
||||
import shadow.org.jdom2.*
|
||||
import shadow.org.jdom2.output.DOMOutputter
|
||||
import shadow.org.jdom2.output.Format
|
||||
import shadow.org.jdom2.output.XMLOutputter
|
||||
import javax.xml.transform.TransformerFactory
|
||||
import javax.xml.transform.dom.*
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import javax.xml.transform.stream.StreamResult
|
||||
|
||||
class JpsCompatiblePlugin : Plugin<Project> {
|
||||
override fun apply(project: Project) {
|
||||
@@ -104,6 +99,7 @@ class JpsCompatibleRootPlugin : Plugin<Project> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private lateinit var projectDir: File
|
||||
private lateinit var platformVersion: String
|
||||
private lateinit var platformBaseNumber: String
|
||||
@@ -123,6 +119,8 @@ class JpsCompatibleRootPlugin : Plugin<Project> {
|
||||
val jpsProject = parse(project, ParserContext(dependencyMappers))
|
||||
.mapLibraries(this::attachPlatformSources, this::attachAsmSources)
|
||||
|
||||
generateKotlinPluginArtifactFile(project).write()
|
||||
|
||||
val files = render(jpsProject, getProjectLibraries(jpsProject))
|
||||
|
||||
removeExistingIdeaLibrariesAndModules()
|
||||
@@ -131,11 +129,7 @@ class JpsCompatibleRootPlugin : Plugin<Project> {
|
||||
copyRunConfigurations()
|
||||
setOptionsForDefaultJunitRunConfiguration(project)
|
||||
|
||||
for (file in files) {
|
||||
val stubFile = file.path
|
||||
stubFile.parentFile.mkdirs()
|
||||
stubFile.writeText(file.text)
|
||||
}
|
||||
files.forEach { it.write() }
|
||||
}
|
||||
|
||||
private fun unpill(project: Project) {
|
||||
|
||||
@@ -3,7 +3,13 @@ package org.jetbrains.kotlin.pill
|
||||
|
||||
import java.io.File
|
||||
|
||||
class PFile(val path: File, val text: String)
|
||||
class PFile(val path: File, val text: String) {
|
||||
fun write() {
|
||||
path.parentFile.mkdirs()
|
||||
path.writeText(text)
|
||||
}
|
||||
}
|
||||
|
||||
fun PFile(path: File, xml: xml) = PFile(path, xml.toString())
|
||||
|
||||
fun render(project: PProject, extraLibraries: List<PLibrary> = emptyList()): List<PFile> {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<log_file alias="idea.log" path="$PROJECT_DIR$/ideaSDK/system-idea/log/idea.log" />
|
||||
<option name="MAIN_CLASS_NAME" value="com.intellij.idea.Main" />
|
||||
<module name="idea-runner" />
|
||||
<option name="VM_PARAMETERS" value="-Xmx1250m -XX:ReservedCodeCacheSize=240m -XX:+HeapDumpOnOutOfMemoryError -ea -Didea.is.internal=true -Didea.debug.mode=true -Didea.system.path=$IDEA_HOME_PATH$/system -Didea.config.path=$IDEA_HOME_PATH$/config -Dapple.laf.useScreenMenuBar=true -Dapple.awt.graphics.UseQuartz=true -Dsun.io.useCanonCaches=false -Dplugin.path=$PROJECT_DIR$/dist/artifacts/Kotlin -Dkotlin.internal.mode.enabled=true" />
|
||||
<option name="VM_PARAMETERS" value="-Xmx1250m -XX:ReservedCodeCacheSize=240m -XX:+HeapDumpOnOutOfMemoryError -ea -Didea.is.internal=true -Didea.debug.mode=true -Didea.system.path=$IDEA_HOME_PATH$/system -Didea.config.path=$IDEA_HOME_PATH$/config -Dapple.laf.useScreenMenuBar=true -Dapple.awt.graphics.UseQuartz=true -Dsun.io.useCanonCaches=false -Dplugin.path=$PROJECT_DIR$/out/artifacts/Kotlin -Dkotlin.internal.mode.enabled=true" />
|
||||
<option name="WORKING_DIRECTORY" value="file://$IDEA_HOME_PATH$" />
|
||||
<RunnerSettings RunnerId="Debug">
|
||||
<option name="DEBUG_PORT" value="" />
|
||||
|
||||
@@ -14,6 +14,7 @@ class xml(val name: String, vararg val args: Pair<String, Any>, block: xml.() ->
|
||||
}
|
||||
|
||||
private val children = mutableListOf<xml>()
|
||||
private var value: Any? = null
|
||||
|
||||
init {
|
||||
@Suppress("UNUSED_EXPRESSION")
|
||||
@@ -28,6 +29,10 @@ class xml(val name: String, vararg val args: Pair<String, Any>, block: xml.() ->
|
||||
children += xml
|
||||
}
|
||||
|
||||
fun raw(text: String) {
|
||||
value = text
|
||||
}
|
||||
|
||||
private fun toElement(): Element {
|
||||
val element = Element(name)
|
||||
|
||||
@@ -35,6 +40,12 @@ class xml(val name: String, vararg val args: Pair<String, Any>, block: xml.() ->
|
||||
element.setAttribute(arg.first, arg.second.toString())
|
||||
}
|
||||
|
||||
require(value == null || children.isEmpty())
|
||||
|
||||
value?.let { value ->
|
||||
element.addContent(value.toString())
|
||||
}
|
||||
|
||||
for (child in children) {
|
||||
element.addContent(child.toElement())
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ jvmTarget = "1.6"
|
||||
|
||||
val nativePlatformVariants: List<String> by rootProject.extra
|
||||
|
||||
// Do not rename, used in JPS importer
|
||||
val fatJarContents by configurations.creating
|
||||
|
||||
dependencies {
|
||||
|
||||
@@ -36,7 +36,6 @@ dist(targetName = the<BasePluginConvention>().archivesBaseName.removePrefix("kot
|
||||
|
||||
ideaPlugin {
|
||||
from(jar)
|
||||
rename("^kotlin-", "")
|
||||
}
|
||||
|
||||
projectTest {
|
||||
|
||||
@@ -6,6 +6,9 @@ apply { plugin("jps-compatible") }
|
||||
|
||||
val robolectricClasspath by configurations.creating
|
||||
|
||||
// Do not rename, used in JPS importer
|
||||
val fatJarContents by configurations.creating
|
||||
|
||||
dependencies {
|
||||
testCompile(intellijCoreDep()) { includeJars("intellij-core") }
|
||||
|
||||
@@ -30,6 +33,8 @@ dependencies {
|
||||
testRuntime(intellijPluginDep("junit")) { includeJars("idea-junit", "resources_en") }
|
||||
|
||||
robolectricClasspath(commonDep("org.robolectric", "robolectric"))
|
||||
|
||||
fatJarContents(project(":kotlin-android-extensions-runtime"))
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
|
||||
@@ -39,7 +39,6 @@ dist(targetName = the<BasePluginConvention>().archivesBaseName.removePrefix("kot
|
||||
|
||||
ideaPlugin {
|
||||
from(jar)
|
||||
rename("^kotlin-", "")
|
||||
}
|
||||
|
||||
projectTest {
|
||||
|
||||
@@ -37,7 +37,6 @@ dist {
|
||||
|
||||
ideaPlugin {
|
||||
from(jar)
|
||||
rename("^kotlin-", "")
|
||||
}
|
||||
|
||||
projectTest {
|
||||
|
||||
@@ -13,6 +13,15 @@ sourceSets {
|
||||
"test" {}
|
||||
}
|
||||
|
||||
// Do not rename, used in JPS importer
|
||||
val fatJarContents by configurations.creating
|
||||
|
||||
dependencies {
|
||||
projectsToShadow.forEach {p ->
|
||||
fatJarContents(project(p)) { isTransitive = false }
|
||||
}
|
||||
}
|
||||
|
||||
runtimeJar {
|
||||
projectsToShadow.forEach {
|
||||
dependsOn("$it:classes")
|
||||
|
||||
@@ -23,7 +23,9 @@ val shrink =
|
||||
val compilerManifestClassPath =
|
||||
"kotlin-stdlib.jar kotlin-reflect.jar kotlin-script-runtime.jar"
|
||||
|
||||
// Do not rename, used in JPS importer
|
||||
val fatJarContents by configurations.creating
|
||||
|
||||
val fatJarContentsStripMetadata by configurations.creating
|
||||
val fatJarContentsStripServices by configurations.creating
|
||||
val fatSourcesJarContents by configurations.creating
|
||||
|
||||
@@ -7,7 +7,8 @@ plugins {
|
||||
`java-base`
|
||||
}
|
||||
|
||||
val projectsToShadow = listOf(
|
||||
// Do not rename, used in JPS importer
|
||||
val projectsToShadow by extra(listOf(
|
||||
":plugins:annotation-based-compiler-plugins-ide-support",
|
||||
":compiler:backend",
|
||||
":compiler:backend-common",
|
||||
@@ -46,9 +47,11 @@ val projectsToShadow = listOf(
|
||||
":compiler:resolution",
|
||||
":compiler:serialization",
|
||||
":compiler:util",
|
||||
":core:util.runtime")
|
||||
":core:util.runtime"))
|
||||
|
||||
// Do not rename, used in JPS importer
|
||||
val packedJars by configurations.creating
|
||||
|
||||
val sideJars by configurations.creating
|
||||
|
||||
dependencies {
|
||||
|
||||
@@ -21,6 +21,7 @@ val projectsToShadow = listOf(
|
||||
":core:util.runtime",
|
||||
":plugins:android-extensions-jps")
|
||||
|
||||
// Do not rename, used in JPS importer
|
||||
val fatJarContents by configurations.creating
|
||||
|
||||
dependencies {
|
||||
|
||||
Reference in New Issue
Block a user