Pill: Import KotlinPlugin artifact

This commit is contained in:
Yan Zhulanow
2018-02-20 01:47:36 +03:00
parent bc78d2c417
commit 07ede20dc5
17 changed files with 242 additions and 25 deletions
+1
View File
@@ -29,6 +29,7 @@ build/
!**/testData/**/*.iml !**/testData/**/*.iml
.idea/libraries/Gradle*.xml .idea/libraries/Gradle*.xml
.idea/libraries/Maven*.xml .idea/libraries/Maven*.xml
.idea/artifacts
.idea/modules .idea/modules
.idea/runConfigurations/JPS_*.xml .idea/runConfigurations/JPS_*.xml
.idea/libraries .idea/libraries
@@ -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))
)
}
+2 -2
View File
@@ -345,9 +345,9 @@ private fun removeDuplicates(roots: List<POrderRoot>): List<POrderRoot> {
return result.toList() 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 dependencies = mutableListOf<DependencyInfo>()
val unprocessed = LinkedList<DependencyInfo>() val unprocessed = LinkedList<DependencyInfo>()
+10 -6
View File
@@ -1,6 +1,7 @@
@file:Suppress("PackageDirectoryMismatch") @file:Suppress("PackageDirectoryMismatch")
package org.jetbrains.kotlin.pill package org.jetbrains.kotlin.pill
import org.gradle.api.Project
import java.io.File import java.io.File
interface PathContext { 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 { override fun invoke(file: File): String {
return file.absolutePath return file.absolutePath.replace(projectDir.absolutePath, "\$PROJECT_DIR\$")
.replace(project.rootDirectory.absolutePath, "\$PROJECT_DIR\$")
} }
} }
@@ -29,11 +32,12 @@ class ModuleContext(val project: PProject, val module: PModule) : PathContext {
return file.absolutePath return file.absolutePath
} }
fun String.withSlash() = if (this.endsWith("/")) this else (this + "/")
return "\$MODULE_DIR\$/" + return "\$MODULE_DIR\$/" +
project.rootDirectory.toRelativeString(module.moduleFile.parentFile).withSlash() + project.rootDirectory.toRelativeString(module.moduleFile.parentFile).withSlash() +
module.rootDirectory.toRelativeString(project.rootDirectory).withSlash() + module.rootDirectory.toRelativeString(project.rootDirectory).withSlash() +
file.toRelativeString(module.rootDirectory) file.toRelativeString(module.rootDirectory)
} }
} }
fun String.withSlash() = if (this.endsWith("/")) this else (this + "/")
fun String.withoutSlash() = this.trimEnd('/')
+4 -10
View File
@@ -4,14 +4,9 @@ import org.gradle.api.Plugin
import org.gradle.api.Project import org.gradle.api.Project
import shadow.org.jdom2.input.SAXBuilder import shadow.org.jdom2.input.SAXBuilder
import shadow.org.jdom2.* import shadow.org.jdom2.*
import shadow.org.jdom2.output.DOMOutputter
import shadow.org.jdom2.output.Format import shadow.org.jdom2.output.Format
import shadow.org.jdom2.output.XMLOutputter import shadow.org.jdom2.output.XMLOutputter
import javax.xml.transform.TransformerFactory
import javax.xml.transform.dom.*
import java.io.File import java.io.File
import java.io.FileOutputStream
import javax.xml.transform.stream.StreamResult
class JpsCompatiblePlugin : Plugin<Project> { class JpsCompatiblePlugin : Plugin<Project> {
override fun apply(project: Project) { override fun apply(project: Project) {
@@ -104,6 +99,7 @@ class JpsCompatibleRootPlugin : Plugin<Project> {
} }
} }
private lateinit var projectDir: File private lateinit var projectDir: File
private lateinit var platformVersion: String private lateinit var platformVersion: String
private lateinit var platformBaseNumber: String private lateinit var platformBaseNumber: String
@@ -123,6 +119,8 @@ class JpsCompatibleRootPlugin : Plugin<Project> {
val jpsProject = parse(project, ParserContext(dependencyMappers)) val jpsProject = parse(project, ParserContext(dependencyMappers))
.mapLibraries(this::attachPlatformSources, this::attachAsmSources) .mapLibraries(this::attachPlatformSources, this::attachAsmSources)
generateKotlinPluginArtifactFile(project).write()
val files = render(jpsProject, getProjectLibraries(jpsProject)) val files = render(jpsProject, getProjectLibraries(jpsProject))
removeExistingIdeaLibrariesAndModules() removeExistingIdeaLibrariesAndModules()
@@ -131,11 +129,7 @@ class JpsCompatibleRootPlugin : Plugin<Project> {
copyRunConfigurations() copyRunConfigurations()
setOptionsForDefaultJunitRunConfiguration(project) setOptionsForDefaultJunitRunConfiguration(project)
for (file in files) { files.forEach { it.write() }
val stubFile = file.path
stubFile.parentFile.mkdirs()
stubFile.writeText(file.text)
}
} }
private fun unpill(project: Project) { private fun unpill(project: Project) {
+7 -1
View File
@@ -3,7 +3,13 @@ package org.jetbrains.kotlin.pill
import java.io.File 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 PFile(path: File, xml: xml) = PFile(path, xml.toString())
fun render(project: PProject, extraLibraries: List<PLibrary> = emptyList()): List<PFile> { 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" /> <log_file alias="idea.log" path="$PROJECT_DIR$/ideaSDK/system-idea/log/idea.log" />
<option name="MAIN_CLASS_NAME" value="com.intellij.idea.Main" /> <option name="MAIN_CLASS_NAME" value="com.intellij.idea.Main" />
<module name="idea-runner" /> <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$" /> <option name="WORKING_DIRECTORY" value="file://$IDEA_HOME_PATH$" />
<RunnerSettings RunnerId="Debug"> <RunnerSettings RunnerId="Debug">
<option name="DEBUG_PORT" value="" /> <option name="DEBUG_PORT" value="" />
+11
View File
@@ -14,6 +14,7 @@ class xml(val name: String, vararg val args: Pair<String, Any>, block: xml.() ->
} }
private val children = mutableListOf<xml>() private val children = mutableListOf<xml>()
private var value: Any? = null
init { init {
@Suppress("UNUSED_EXPRESSION") @Suppress("UNUSED_EXPRESSION")
@@ -28,6 +29,10 @@ class xml(val name: String, vararg val args: Pair<String, Any>, block: xml.() ->
children += xml children += xml
} }
fun raw(text: String) {
value = text
}
private fun toElement(): Element { private fun toElement(): Element {
val element = Element(name) 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()) element.setAttribute(arg.first, arg.second.toString())
} }
require(value == null || children.isEmpty())
value?.let { value ->
element.addContent(value.toString())
}
for (child in children) { for (child in children) {
element.addContent(child.toElement()) element.addContent(child.toElement())
} }
@@ -9,6 +9,7 @@ jvmTarget = "1.6"
val nativePlatformVariants: List<String> by rootProject.extra val nativePlatformVariants: List<String> by rootProject.extra
// Do not rename, used in JPS importer
val fatJarContents by configurations.creating val fatJarContents by configurations.creating
dependencies { dependencies {
@@ -36,7 +36,6 @@ dist(targetName = the<BasePluginConvention>().archivesBaseName.removePrefix("kot
ideaPlugin { ideaPlugin {
from(jar) from(jar)
rename("^kotlin-", "")
} }
projectTest { projectTest {
@@ -6,6 +6,9 @@ apply { plugin("jps-compatible") }
val robolectricClasspath by configurations.creating val robolectricClasspath by configurations.creating
// Do not rename, used in JPS importer
val fatJarContents by configurations.creating
dependencies { dependencies {
testCompile(intellijCoreDep()) { includeJars("intellij-core") } testCompile(intellijCoreDep()) { includeJars("intellij-core") }
@@ -30,6 +33,8 @@ dependencies {
testRuntime(intellijPluginDep("junit")) { includeJars("idea-junit", "resources_en") } testRuntime(intellijPluginDep("junit")) { includeJars("idea-junit", "resources_en") }
robolectricClasspath(commonDep("org.robolectric", "robolectric")) robolectricClasspath(commonDep("org.robolectric", "robolectric"))
fatJarContents(project(":kotlin-android-extensions-runtime"))
} }
sourceSets { sourceSets {
-1
View File
@@ -39,7 +39,6 @@ dist(targetName = the<BasePluginConvention>().archivesBaseName.removePrefix("kot
ideaPlugin { ideaPlugin {
from(jar) from(jar)
rename("^kotlin-", "")
} }
projectTest { projectTest {
@@ -37,7 +37,6 @@ dist {
ideaPlugin { ideaPlugin {
from(jar) from(jar)
rename("^kotlin-", "")
} }
projectTest { projectTest {
+9
View File
@@ -13,6 +13,15 @@ sourceSets {
"test" {} "test" {}
} }
// Do not rename, used in JPS importer
val fatJarContents by configurations.creating
dependencies {
projectsToShadow.forEach {p ->
fatJarContents(project(p)) { isTransitive = false }
}
}
runtimeJar { runtimeJar {
projectsToShadow.forEach { projectsToShadow.forEach {
dependsOn("$it:classes") dependsOn("$it:classes")
+2
View File
@@ -23,7 +23,9 @@ val shrink =
val compilerManifestClassPath = val compilerManifestClassPath =
"kotlin-stdlib.jar kotlin-reflect.jar kotlin-script-runtime.jar" "kotlin-stdlib.jar kotlin-reflect.jar kotlin-script-runtime.jar"
// Do not rename, used in JPS importer
val fatJarContents by configurations.creating val fatJarContents by configurations.creating
val fatJarContentsStripMetadata by configurations.creating val fatJarContentsStripMetadata by configurations.creating
val fatJarContentsStripServices by configurations.creating val fatJarContentsStripServices by configurations.creating
val fatSourcesJarContents by configurations.creating val fatSourcesJarContents by configurations.creating
+5 -2
View File
@@ -7,7 +7,8 @@ plugins {
`java-base` `java-base`
} }
val projectsToShadow = listOf( // Do not rename, used in JPS importer
val projectsToShadow by extra(listOf(
":plugins:annotation-based-compiler-plugins-ide-support", ":plugins:annotation-based-compiler-plugins-ide-support",
":compiler:backend", ":compiler:backend",
":compiler:backend-common", ":compiler:backend-common",
@@ -46,9 +47,11 @@ val projectsToShadow = listOf(
":compiler:resolution", ":compiler:resolution",
":compiler:serialization", ":compiler:serialization",
":compiler:util", ":compiler:util",
":core:util.runtime") ":core:util.runtime"))
// Do not rename, used in JPS importer
val packedJars by configurations.creating val packedJars by configurations.creating
val sideJars by configurations.creating val sideJars by configurations.creating
dependencies { dependencies {
+1
View File
@@ -21,6 +21,7 @@ val projectsToShadow = listOf(
":core:util.runtime", ":core:util.runtime",
":plugins:android-extensions-jps") ":plugins:android-extensions-jps")
// Do not rename, used in JPS importer
val fatJarContents by configurations.creating val fatJarContents by configurations.creating
dependencies { dependencies {