Wizard: add packForXCodeTaskGeneration

This commit is contained in:
Ilya Kirillov
2020-03-23 17:11:09 +03:00
parent 0ab91821c8
commit e98b0782c1
8 changed files with 141 additions and 7 deletions
@@ -52,6 +52,9 @@ inline fun <A : Any, B : Any, R : Any> TaskResult<A>.mappendM(
infix fun <T : Any> TaskResult<*>.andThen(other: TaskResult<T>): TaskResult<T> =
mappendM(other) { _, _ -> other }
infix fun <T : Any> TaskResult<T>.andThenIgnoring(other: TaskResult<Unit>): TaskResult<T> =
mappendM(other) { _, _ -> this }
operator fun <T : Any> TaskResult<List<T>>.plus(other: TaskResult<List<T>>): TaskResult<Unit> =
mappend(other) { _, _ -> Unit }
@@ -58,7 +58,7 @@ data class ValidationError(val validationMessage: String) : Error() {
data class ProjectImportingError(override val message: String) : Error()
data class InvalidModuleDependencyError(val from: Module, val to: Module) : Error() {
data class InvalidModuleDependencyError(val from: Module, val to: Module, val reason: String? = null) : Error() {
override val message: String
get() = "Invalid module dependency from module ${from.name} to ${to.name}"
get() = "Invalid module dependency from module ${from.name} to ${to.name}" + reason?.let { ": $it" }
}
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.tools.projectWizard.plugins.printer.BuildFilePrinter
import org.jetbrains.kotlin.tools.projectWizard.plugins.printer.GradlePrinter
import org.jetbrains.kotlin.tools.projectWizard.plugins.printer.MavenPrinter
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.DefaultRepository
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.Module
import java.nio.file.Path
interface FileIR : BuildSystemIR, IrsOwner
@@ -20,6 +21,7 @@ data class BuildFileIR(
val name: String,
val directoryPath: Path,
val modules: ModulesStructureIR,
val fromModules: List<Module>,
val pom: PomIR,
override val irs: PersistentList<BuildSystemIR>
) : FileIR {
@@ -22,7 +22,15 @@ data class RawGradleIR(
override fun GradlePrinter.renderGradle() = renderer()
}
data class CreateGradleValueIR(val name: String, val body: GradleIR) : GradleIR {
fun rawIR(ir: String) = RawGradleIR { +ir }
fun rawIR(ir: GradlePrinter.() -> String) = RawGradleIR { +ir() }
fun MutableList<BuildSystemIR>.addRawIR(ir: GradlePrinter.() -> String) {
add(RawGradleIR { +ir() })
}
class CreateGradleValueIR(val name: String, val body: GradleIR) : GradleIR {
override fun GradlePrinter.renderGradle() {
when (dsl) {
GradlePrinter.GradleDsl.KOTLIN -> {
@@ -46,6 +54,8 @@ data class GradleCallIr(
val name: String,
val parameters: List<BuildSystemIR> = emptyList()
) : GradleIR {
constructor(name: String, vararg parameters: BuildSystemIR) : this(name, parameters.toList())
override fun GradlePrinter.renderGradle() {
call(name, forceBrackets = true) {
parameters.list { it.render(this) }
@@ -68,8 +78,6 @@ data class GradleNewInstanceCall(
}
data class GradleSectionIR(
val name: String,
val body: BodyIR
@@ -136,6 +144,14 @@ data class GradleImportIR(val import: String) : GradleIR {
}
}
data class GradleBinaryExpressionIR(val left: BuildSystemIR, val op: String, val right: BuildSystemIR) : GradleIR {
override fun GradlePrinter.renderGradle() {
left.render(this)
+" $op "
right.render(this)
}
}
interface BuildScriptIR : BuildSystemIR
data class BuildScriptDependencyIR(val dependencyIR: GradleIR) : BuildScriptIR, BuildSystemIR by dependencyIR
@@ -40,11 +40,34 @@ data class GradleByClassTasksAccessIR(
}
}
data class GradleByClassTasksCreateIR(
val taskName: String,
val taskClass: String
) : GradleTaskAccessIR {
override fun GradlePrinter.renderGradle() {
when (dsl) {
GradlePrinter.GradleDsl.KOTLIN -> {
+"val $taskName by tasks.creating($taskClass::class)"
}
GradlePrinter.GradleDsl.GROOVY -> {
+"task($taskName, type: $taskClass)"
}
}
}
}
data class GradleConfigureTaskIR(
val taskAccess: GradleTaskAccessIR,
val dependsOn: List<BuildSystemIR> = emptyList(),
val irs: List<BuildSystemIR> = emptyList()
) : GradleIR, FreeIR {
constructor(
taskAccess: GradleTaskAccessIR,
dependsOn: List<BuildSystemIR> = emptyList(),
createIrs: MutableList<BuildSystemIR>.() -> Unit = {}
) : this(taskAccess, dependsOn, mutableListOf<BuildSystemIR>().apply(createIrs))
override fun GradlePrinter.renderGradle() {
taskAccess.render(this)
+" "
@@ -1,6 +1,7 @@
package org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.StdlibType
import java.util.*
//TODO maybe split into interfaces like it made with module configurators
@Suppress("EnumEntryName")
@@ -33,6 +34,9 @@ enum class ModuleSubType(val moduleType: ModuleType) {
common(ModuleType.common)
}
val ModuleSubType.isIOS: Boolean
get() = this in EnumSet.of(ModuleSubType.iosX64, ModuleSubType.iosArm32, ModuleSubType.iosArm64)
fun ModuleType.correspondingStdlib(): StdlibType? = when (this) {
ModuleType.jvm -> StdlibType.StdlibJdk8
ModuleType.js -> StdlibType.StdlibJs
@@ -58,6 +58,9 @@ class ModulesToIRsConverter(
return data.isSingleRootModuleMode
}
private val irsToAddToModules = hashMapOf<Module, MutableList<BuildSystemIR>>()
private val moduleToBuildFile = hashMapOf<Module, BuildFileIR>()
private fun calculatePathForModule(module: Module, rootPath: Path) = when {
needFlattening && module.isRootModule -> data.projectPath
else -> rootPath / module.name
@@ -75,6 +78,11 @@ class ModulesToIRsConverter(
}.map { it.flatten() }.map { buildFiles ->
if (needExplicitRootBuildFile) buildFiles + createRootBuildFile()
else buildFiles
}.map { buildFiles ->
buildFiles.map { buildFile ->
val irs = buildFile.fromModules.flatMap { irsToAddToModules[it]?.toList() ?: emptyList() }
buildFile.withIrs(irs)
}
}
}
@@ -83,6 +91,7 @@ class ModulesToIRsConverter(
projectName,
projectPath,
RootFileModuleStructureIR(persistentListOf()),
emptyList(),
pomIr,
rootBuildFileIrs.toPersistentList()
)
@@ -112,6 +121,7 @@ class ModulesToIRsConverter(
with(dependencyType) {
@Suppress("DEPRECATION")
with(unsafeSettingWriter) { runArbitraryTask(module, to, data).ensure() }
irsToAddToModules.getOrPut(to) { mutableListOf() } += createToIRs(module, to, data).get()
createDependencyIrs(module, to, data)
}
}.sequence().map { it.flatten() }
@@ -155,9 +165,12 @@ class ModulesToIRsConverter(
moduleIr,
persistentListOf()
),
listOf(module),
data.pomIr.copy(artifactId = module.name),
createBuildFileIRs(module, state)
)
).also {
moduleToBuildFile[module] = it
}
}
module.subModules.mapSequence { subModule ->
@@ -193,12 +206,19 @@ class ModulesToIRsConverter(
targetModuleIrs,
persistentListOf()
),
module.subModules + module,
pomIr,
buildPersistenceList {
+createBuildFileIRs(module, state)
module.subModules.forEach { +createBuildFileIRs(it, state) }
}
).asSingletonList().asSuccess()
).also { buildFile ->
moduleToBuildFile[module] = buildFile
module.subModules.forEach { subModule ->
moduleToBuildFile[subModule] = buildFile
}
}.asSingletonList().asSuccess()
}
private fun Writer.createTargetModule(target: Module, modulePath: Path): MultiplatformModuleIR {
@@ -11,9 +11,13 @@ import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.BuildSystemIR
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.DependencyType
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.GradleRootProjectDependencyIR
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.ModuleDependencyIR
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle.*
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.*
import org.jetbrains.kotlin.tools.projectWizard.plugins.buildSystem.isGradle
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ModulesToIrConversionData
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.isIOS
import org.jetbrains.kotlin.tools.projectWizard.plugins.printer.GradlePrinter
import kotlin.collections.buildList
import kotlin.reflect.KClass
sealed class ModuleDependencyType(
@@ -41,6 +45,9 @@ sealed class ModuleDependencyType(
open fun SettingsWriter.runArbitraryTask(from: Module, to: Module, data: ModulesToIrConversionData): TaskResult<Unit> =
UNIT_SUCCESS
open fun Reader.createToIRs(from: Module, to: Module, data: ModulesToIrConversionData): TaskResult<List<BuildSystemIR>> =
Success(emptyList())
object JVMSinglePlatformToJVMSinglePlatform : ModuleDependencyType(
from = JvmSinglePlatformModuleConfigurator::class,
to = JvmSinglePlatformModuleConfigurator::class
@@ -67,6 +74,65 @@ sealed class ModuleDependencyType(
.setValue(IOSSinglePlatformModuleConfigurator.DependentModuleReference(to))
UNIT_SUCCESS
}
@OptIn(ExperimentalStdlibApi::class)
override fun Reader.createToIRs(from: Module, to: Module, data: ModulesToIrConversionData): TaskResult<List<BuildSystemIR>> {
val iosTargetName = to.subModules.firstOrNull { module ->
module.configurator.safeAs<SimpleTargetConfigurator>()?.moduleSubType?.isIOS == true
}?.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")))
add(
CreateGradleValueIR(
"mode",
GradleBinaryExpressionIR(
RawGradleIR { +"System.getenv("; +"CONFIGURATION".quotified; +")" },
"?:",
GradleStringConstIR("DEBUG")
)
)
)
add(
CreateGradleValueIR(
"framework",
RawGradleIR {
+"kotlin.targets"
when (dsl) {
GradlePrinter.GradleDsl.KOTLIN -> +""".getByName<KotlinNativeTarget>("$iosTargetName")"""
GradlePrinter.GradleDsl.GROOVY -> +"['$iosTargetName']"
}
+".binaries.getFramework(mode)"
}
)
)
addRawIR { "inputs.property(${"mode".quotified}, mode)" }
addRawIR { "dependsOn(framework.linkTask)" }
add(
CreateGradleValueIR(
"targetDir",
GradleCallIr("File", rawIR("buildDir"), GradleStringConstIR("xcode-frameworks"))
)
)
addRawIR { "from({ framework.outputDirectory })" }
addRawIR { "into(targetDir)" }
}
val dependency = rawIR {
when (dsl) {
GradlePrinter.GradleDsl.KOTLIN -> """tasks.getByName("build").dependsOn(packForXcode)"""
GradlePrinter.GradleDsl.GROOVY -> "tasks['build'].dependsOn(packForXcode)"
}
}
return buildList {
add(packForXcodeTask)
add(dependency)
add(GradleImportIR("org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget"))
}.asSuccess()
}
}
companion object {