Wizard: introduce gradle IR builder

This commit is contained in:
Ilya Kirillov
2020-04-10 15:34:15 +03:00
parent aa3cdc09fc
commit e6a3caa267
11 changed files with 144 additions and 157 deletions
@@ -79,4 +79,4 @@ task(packForXcode, type: Sync) {
from({ framework.outputDirectory }) from({ framework.outputDirectory })
into(targetDir) into(targetDir)
} }
tasks.getByName("build").dependsOn(packForXcode) tasks.getByName('build').dependsOn(packForXcode)
@@ -1,29 +0,0 @@
package org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle
import org.jetbrains.kotlin.tools.projectWizard.core.ListBuilder
import org.jetbrains.kotlin.tools.projectWizard.core.buildList
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.BuildSystemIR
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.render
import org.jetbrains.kotlin.tools.projectWizard.plugins.printer.GradlePrinter
data class BodyIR(
val body: List<BuildSystemIR>
) : GradleIR {
constructor(vararg body: BuildSystemIR) : this(body.toList())
override fun GradlePrinter.renderGradle() {
inBrackets {
body.listNl()
}
}
}
fun buildBody(builder: ListBuilder<BuildSystemIR>.() -> Unit) =
BodyIR(buildList(builder))
fun BodyIR.renderIfNotEmpty(printer: GradlePrinter) =
takeIf { it.isNotEmpty() }?.render(printer)
fun BodyIR.isEmpty() = body.isEmpty()
fun BodyIR.isNotEmpty() = body.isNotEmpty()
@@ -23,15 +23,7 @@ data class RawGradleIR(
override fun GradlePrinter.renderGradle() = renderer() override fun GradlePrinter.renderGradle() = renderer()
} }
fun rawIR(@NonNls ir: String) = RawGradleIR { +ir } class CreateGradleValueIR(@NonNls val name: String, val body: BuildSystemIR) : GradleIR {
fun rawIR(ir: GradlePrinter.() -> String) = RawGradleIR { +ir() }
fun MutableList<BuildSystemIR>.addRawIR(ir: GradlePrinter.() -> String) {
add(RawGradleIR { +ir() })
}
class CreateGradleValueIR(@NonNls val name: String, val body: GradleIR) : GradleIR {
override fun GradlePrinter.renderGradle() { override fun GradlePrinter.renderGradle() {
when (dsl) { when (dsl) {
GradlePrinter.GradleDsl.KOTLIN -> { GradlePrinter.GradleDsl.KOTLIN -> {
@@ -87,17 +79,12 @@ data class GradleNewInstanceCall(
data class GradleSectionIR( data class GradleSectionIR(
@NonNls val name: String, @NonNls val name: String,
val body: BodyIR val irs: List<BuildSystemIR>
) : GradleIR, FreeIR { ) : GradleIR, FreeIR {
constructor(name: String, bodyBuilder: MutableList<BuildSystemIR>.() -> Unit) : this(
name,
BodyIR(mutableListOf<BuildSystemIR>().apply(bodyBuilder))
)
override fun GradlePrinter.renderGradle() { override fun GradlePrinter.renderGradle() {
+name sectionCall(name) {
+" " irs.listNl()
body.render(this) }
} }
} }
@@ -0,0 +1,58 @@
/*
* 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.
*/
package org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle
import org.jetbrains.annotations.NonNls
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.BuildSystemIR
import org.jetbrains.kotlin.tools.projectWizard.plugins.printer.GradlePrinter
typealias IRsListBuilderFunction = GradleIRListBuilder.() -> Unit
fun IRsListBuilderFunction.build() = GradleIRListBuilder.build(this)
interface GradleIRBuilderBase {
fun const(const: String) = GradleStringConstIR(const)
fun raw(renderer: GradlePrinter.() -> Unit) = RawGradleIR(renderer)
fun raw(string: String) = RawGradleIR { +string }
fun new(@NonNls name: String, vararg parameters: BuildSystemIR) = GradleCallIr(name, parameters.toList(), isConstructorCall = true)
fun new(@NonNls name: String, parameters: IRsListBuilderFunction) = new(name, *parameters.build().toTypedArray())
fun fromString(renderer: GradlePrinter.() -> String) = RawGradleIR { +renderer() }
}
class GradleIRListBuilder private constructor() : GradleIRBuilderBase {
private val irs = mutableListOf<BuildSystemIR>()
operator fun String.invoke(inner: IRsListBuilderFunction) =
GradleSectionIR(this, build(inner)).also(irs::add)
operator fun String.invoke(vararg parameters: BuildSystemIR) =
GradleCallIr(this, parameters.toList()).also(irs::add)
infix fun String.assign(assignee: BuildSystemIR) =
GradleAssignmentIR(this, assignee).also(irs::add)
infix fun String.createValue(assignee: BuildSystemIR) =
CreateGradleValueIR(this, assignee).also(irs::add)
operator fun String.unaryPlus() = RawGradleIR { +this@unaryPlus }.also(irs::add)
operator fun BuildSystemIR.unaryPlus() = also(irs::add)
fun addRaw(raw: GradlePrinter.() -> Unit) = RawGradleIR(raw).also(irs::add)
fun addRaw(@NonNls raw: String) = RawGradleIR { +raw }.also(irs::add)
fun import(@NonNls import: String) = GradleImportIR(import).also(irs::add)
fun build(): List<BuildSystemIR> = irs
companion object {
fun build(inner: IRsListBuilderFunction) = GradleIRListBuilder().apply(inner).build()
}
}
fun irsList(inner: IRsListBuilderFunction): List<BuildSystemIR> =
GradleIRListBuilder.build(inner)
@@ -66,8 +66,8 @@ data class GradleConfigureTaskIR(
constructor( constructor(
taskAccess: GradleTaskAccessIR, taskAccess: GradleTaskAccessIR,
dependsOn: List<BuildSystemIR> = emptyList(), dependsOn: List<BuildSystemIR> = emptyList(),
createIrs: MutableList<BuildSystemIR>.() -> Unit = {} createIrs: IRsListBuilderFunction
) : this(taskAccess, dependsOn, mutableListOf<BuildSystemIR>().apply(createIrs)) ) : this(taskAccess, dependsOn, createIrs.build())
override fun GradlePrinter.renderGradle() { override fun GradlePrinter.renderGradle() {
taskAccess.render(this) taskAccess.render(this)
@@ -1,11 +1,14 @@
package org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle.multiplatform package org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle.multiplatform
import kotlinx.collections.immutable.PersistentList import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.toPersistentList
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.BuildSystemIR import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.BuildSystemIR
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.IrsOwner import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.IrsOwner
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.KotlinIR import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.KotlinIR
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle.GradleCallIr import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle.GradleCallIr
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle.GradleIR import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle.GradleIR
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle.IRsListBuilderFunction
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle.build
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.withIrs import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.withIrs
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ModuleSubType import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ModuleSubType
import org.jetbrains.kotlin.tools.projectWizard.plugins.printer.GradlePrinter import org.jetbrains.kotlin.tools.projectWizard.plugins.printer.GradlePrinter
@@ -45,6 +48,9 @@ data class DefaultTargetConfigurationIR(
override val targetName: String override val targetName: String
get() = targetAccess.nonDefaultName ?: targetAccess.type.name get() = targetAccess.nonDefaultName ?: targetAccess.type.name
constructor(targetAccess: TargetAccessIR, irs: IRsListBuilderFunction)
: this(targetAccess, irs.build().toPersistentList())
override fun withReplacedIrs(irs: PersistentList<BuildSystemIR>): DefaultTargetConfigurationIR = override fun withReplacedIrs(irs: PersistentList<BuildSystemIR>): DefaultTargetConfigurationIR =
copy(irs = irs) copy(irs = irs)
@@ -67,6 +73,9 @@ data class NonDefaultTargetConfigurationIR(
override fun withReplacedIrs(irs: PersistentList<BuildSystemIR>): NonDefaultTargetConfigurationIR = override fun withReplacedIrs(irs: PersistentList<BuildSystemIR>): NonDefaultTargetConfigurationIR =
copy(irs = irs) copy(irs = irs)
constructor(variableName: String, targetName: String, irs: IRsListBuilderFunction)
: this(variableName, targetName, irs.build().toPersistentList())
override fun GradlePrinter.renderGradle() { override fun GradlePrinter.renderGradle() {
if (irs.isNotEmpty()) { if (irs.isNotEmpty()) {
+variableName +variableName
@@ -9,21 +9,17 @@ import org.jetbrains.annotations.NonNls
import org.jetbrains.kotlin.tools.projectWizard.core.buildList import org.jetbrains.kotlin.tools.projectWizard.core.buildList
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle.* import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle.*
fun runTaskIrs(@NonNls mainClass: String, classPath: BuildSystemIR? = null) = buildList<BuildSystemIR> { fun runTaskIrs(@NonNls mainClass: String, classPath: BuildSystemIR? = null) = irsList {
+ApplicationPluginIR(mainClass) +ApplicationPluginIR(mainClass)
+GradleSectionIR("application", buildBody { "application" {
+GradleAssignmentIR("mainClassName", GradleStringConstIR(mainClass)) "mainClassName" assign const(mainClass)
}) }
if (classPath != null) { if (classPath != null) {
+GradleConfigureTaskIR( +GradleConfigureTaskIR(GradleByNameTaskAccessIR("run", "JavaExec")) {
GradleByNameTaskAccessIR( "classpath" assign classPath
name = "run", }
taskClass = "JavaExec"
),
irs = listOf(GradleAssignmentIR("classpath", classPath))
)
} }
} }
@@ -9,13 +9,11 @@ package org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators
import org.jetbrains.annotations.NonNls import org.jetbrains.annotations.NonNls
import org.jetbrains.kotlin.tools.projectWizard.KotlinNewProjectWizardBundle import org.jetbrains.kotlin.tools.projectWizard.KotlinNewProjectWizardBundle
import org.jetbrains.kotlin.tools.projectWizard.core.Reader import org.jetbrains.kotlin.tools.projectWizard.core.Reader
import org.jetbrains.kotlin.tools.projectWizard.core.buildList
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.BuildSystemIR import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.BuildSystemIR
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.KotlinBuildSystemPluginIR import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.KotlinBuildSystemPluginIR
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle.RawGradleIR import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle.irsList
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle.rawIR
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ModulesToIrConversionData
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ModuleType import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ModuleType
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ModulesToIrConversionData
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.Module import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.Module
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.ModuleKind import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.ModuleKind
@@ -47,13 +45,11 @@ object JsSingleplatformModuleConfigurator : JSConfigurator, ModuleConfiguratorWi
reader: Reader, reader: Reader,
configurationData: ModulesToIrConversionData, configurationData: ModulesToIrConversionData,
module: Module module: Module
): List<BuildSystemIR> = buildList { ): List<BuildSystemIR> = irsList {
+RawGradleIR { "kotlin" {
sectionCall("kotlin", needIndent = true) { "js" {
sectionCall("js", needIndent = true) { +"browser {}"
+"browser {}"; nlIndented() +"binaries.executable()"
+"binaries.executable()"
}
} }
} }
} }
@@ -25,16 +25,12 @@ class RealNativeTargetConfigurator private constructor(
override val isDesktopTarget: Boolean override val isDesktopTarget: Boolean
get() = moduleSubType.isNativeDesktop get() = moduleSubType.isNativeDesktop
override fun createInnerTargetIrs(reader: Reader, module: Module): List<BuildSystemIR> = if (moduleSubType.isIOS) { override fun createInnerTargetIrs(reader: Reader, module: Module): List<BuildSystemIR> = if (moduleSubType.isIOS) irsList {
listOf( "binaries" {
GradleSectionIR("binaries") { "framework" {
add( "baseName" assign const(module.parent!!.name)
GradleSectionIR("framework") {
add(GradleAssignmentIR("baseName", GradleStringConstIR(module.parent!!.name)))
}
)
} }
) }
} else emptyList() } else emptyList()
companion object { companion object {
@@ -62,12 +58,11 @@ object NativeForCurrentSystemTarget : NativeTargetConfigurator, SingleCoexistenc
val moduleName = module.name val moduleName = module.name
val variableName = "${moduleName}Target" val variableName = "${moduleName}Target"
return buildList { return irsList {
+CreateGradleValueIR("hostOs", RawGradleIR { +"System.getProperty(\"os.name\")" }) "hostOs" createValue raw("System.getProperty(\"os.name\")")
+CreateGradleValueIR("isMingwX64", RawGradleIR { +"hostOs.startsWith(\"Windows\")" }) "isMingwX64" createValue raw("hostOs.startsWith(\"Windows\")")
//TODO do not use RawGradleIR here addRaw {
+RawGradleIR {
when (dsl) { when (dsl) {
GradlePrinter.GradleDsl.KOTLIN -> { GradlePrinter.GradleDsl.KOTLIN -> {
+"val $variableName = when " +"val $variableName = when "
@@ -102,9 +97,9 @@ object NativeForCurrentSystemTarget : NativeTargetConfigurator, SingleCoexistenc
reader: Reader, reader: Reader,
configurationData: ModulesToIrConversionData, configurationData: ModulesToIrConversionData,
module: Module module: Module
): List<BuildSystemIR> = buildList { ): List<BuildSystemIR> = irsList {
if (configurationData.buildSystemType == BuildSystemType.GradleGroovyDsl) { if (configurationData.buildSystemType == BuildSystemType.GradleGroovyDsl) {
+GradleImportIR("org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTargetWithTests") import("org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTargetWithTests")
} }
} }
} }
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle.*
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle.multiplatform.DefaultTargetConfigurationIR import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle.multiplatform.DefaultTargetConfigurationIR
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle.multiplatform.TargetAccessIR import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle.multiplatform.TargetAccessIR
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.JsBrowserTargetConfigurator.isApplication import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.JsBrowserTargetConfigurator.isApplication
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.JsNodeTargetConfigurator.isApplication
import org.jetbrains.kotlin.tools.projectWizard.phases.GenerationPhase import org.jetbrains.kotlin.tools.projectWizard.phases.GenerationPhase
import org.jetbrains.kotlin.tools.projectWizard.plugins.buildSystem.buildSystemType import org.jetbrains.kotlin.tools.projectWizard.plugins.buildSystem.buildSystemType
import org.jetbrains.kotlin.tools.projectWizard.plugins.buildSystem.isGradle import org.jetbrains.kotlin.tools.projectWizard.plugins.buildSystem.isGradle
@@ -105,19 +106,16 @@ object JsBrowserTargetConfigurator : JsTargetConfigurator, ModuleConfiguratorWit
override fun Reader.createTargetIrs( override fun Reader.createTargetIrs(
module: Module module: Module
): List<BuildSystemIR> = buildList { ): List<BuildSystemIR> = irsList {
+DefaultTargetConfigurationIR( +DefaultTargetConfigurationIR(
module.createTargetAccessIr(ModuleSubType.js), module.createTargetAccessIr(ModuleSubType.js)
buildPersistenceList { ) {
+RawGradleIR { "browser" {
sectionCall("browser", needIndent = true) { if (isApplication(module)) {
if (isApplication(module)) { +"binaries.executable()"
+"binaries.executable()"
}
}
} }
} }
) }
} }
} }
@@ -133,19 +131,16 @@ object JsNodeTargetConfigurator : JsTargetConfigurator {
override fun Reader.createTargetIrs( override fun Reader.createTargetIrs(
module: Module module: Module
): List<BuildSystemIR> = buildList { ): List<BuildSystemIR> = irsList {
+DefaultTargetConfigurationIR( +DefaultTargetConfigurationIR(
module.createTargetAccessIr(ModuleSubType.js), module.createTargetAccessIr(ModuleSubType.js)
buildPersistenceList { ) {
+RawGradleIR { "nodejs" {
sectionCall("nodejs", needIndent = true) { if (isApplication(module)) {
if (isApplication(module)) { +"binaries.executable()"
+"binaries.executable()"
}
}
} }
} }
) }
} }
} }
@@ -168,20 +163,18 @@ object JvmTargetConfigurator : JvmModuleConfigurator,
override fun createInnerTargetIrs( override fun createInnerTargetIrs(
reader: Reader, reader: Reader,
module: Module module: Module
): List<BuildSystemIR> = buildList { ): List<BuildSystemIR> = irsList {
reader { reader {
withSettingsOf(module) { withSettingsOf(module) {
val targetVersionValue = JvmModuleConfigurator.targetJvmVersion.reference.settingValue.value val targetVersionValue = JvmModuleConfigurator.targetJvmVersion.reference.settingValue.value
if (buildSystemType.isGradle) { if (buildSystemType.isGradle) {
+GradleSectionIR( "compilations.all" {
"compilations.all", "kotlinOptions.jvmTarget" assign GradleStringConstIR(targetVersionValue)
BodyIR( }
GradleAssignmentIR("kotlinOptions.jvmTarget", GradleStringConstIR(targetVersionValue))
)
)
} }
if (Settings.javaSupport.reference.settingValue) { if (Settings.javaSupport.reference.settingValue) {
+GradleCallIr("withJava") "withJava"()
} }
} }
} }
@@ -81,51 +81,33 @@ sealed class ModuleDependencyType(
module.configurator.safeAs<SimpleTargetConfigurator>()?.moduleSubType?.isIOS == true module.configurator.safeAs<SimpleTargetConfigurator>()?.moduleSubType?.isIOS == true
}?.name ?: return Failure(InvalidModuleDependencyError(from, to, "Module ${to.name} should contain at least one iOS target")) }?.name ?: return Failure(InvalidModuleDependencyError(from, to, "Module ${to.name} should contain at least one iOS target"))
val packForXcodeTask = GradleConfigureTaskIR(GradleByClassTasksCreateIR("packForXcode", "Sync")) {
add(GradleAssignmentIR("group", GradleStringConstIR("build"))) return irsList {
add( +GradleConfigureTaskIR(GradleByClassTasksCreateIR("packForXcode", "Sync")) {
CreateGradleValueIR( "group" assign const("build")
"mode", "mode" createValue GradleBinaryExpressionIR(
GradleBinaryExpressionIR( raw { +"System.getenv("; +"CONFIGURATION".quotified; +")" },
RawGradleIR { +"System.getenv("; +"CONFIGURATION".quotified; +")" }, "?:",
"?:", const("DEBUG")
GradleStringConstIR("DEBUG")
)
) )
) "framework" createValue raw {
+"kotlin.targets."
add( when (dsl) {
CreateGradleValueIR( GradlePrinter.GradleDsl.KOTLIN -> +"""getByName<KotlinNativeTarget>("$iosTargetName")"""
"framework", GradlePrinter.GradleDsl.GROOVY -> +iosTargetName
RawGradleIR {
+"kotlin.targets."
when (dsl) {
GradlePrinter.GradleDsl.KOTLIN -> +"""getByName<KotlinNativeTarget>("$iosTargetName")"""
GradlePrinter.GradleDsl.GROOVY -> +iosTargetName
}
+".binaries.getFramework(mode)"
} }
) +".binaries.getFramework(mode)"
) };
addRawIR { "inputs.property(${"mode".quotified}, mode)" }
addRawIR { "dependsOn(framework.linkTask)" }
add(
CreateGradleValueIR(
"targetDir",
GradleCallIr("File", rawIR("buildDir"), GradleStringConstIR("xcode-frameworks"), isConstructorCall = true)
)
)
addRawIR { "from({ framework.outputDirectory })" }
addRawIR { "into(targetDir)" }
}
val dependency = rawIR { """tasks.getByName("build").dependsOn(packForXcode)""" } addRaw { +"inputs.property(${"mode".quotified}, mode)" }
addRaw("dependsOn(framework.linkTask)")
"targetDir" createValue new("File", raw("buildDir"), const("xcode-frameworks"))
addRaw("from({ framework.outputDirectory })")
addRaw("into(targetDir)")
}
addRaw { +"""tasks.getByName(${"build".quotified}).dependsOn(packForXcode)""" }
import("org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget")
return buildList {
add(packForXcodeTask)
add(dependency)
add(GradleImportIR("org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget"))
}.asSuccess() }.asSuccess()
} }
} }