Wizard: introduce mobile mpp module template & allow module templates for mpp modules
This commit is contained in:
+3
-2
@@ -165,13 +165,14 @@ private class ModuleTemplateComponent(
|
||||
private object NoneTemplate : Template() {
|
||||
override val title = KotlinNewProjectWizardUIBundle.message("module.settings.template.none")
|
||||
override val description: String = ""
|
||||
override val moduleTypes: Set<ModuleType> = ModuleType.ALL
|
||||
override fun isSupportedByModuleType(module: Module): Boolean = true
|
||||
|
||||
override val id: String = "none"
|
||||
}
|
||||
|
||||
fun Reader.availableTemplatesFor(module: Module) =
|
||||
TemplatesPlugin.templates.propertyValue.values.filter { template ->
|
||||
module.configurator.moduleType in template.moduleTypes
|
||||
template.isSupportedByModuleType(module)
|
||||
}
|
||||
|
||||
|
||||
|
||||
+1
@@ -17,6 +17,7 @@ version = '1.0-SNAPSHOT'
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
maven { url 'KOTLIN_REPO' }
|
||||
}
|
||||
|
||||
+1
@@ -17,6 +17,7 @@ version = "1.0-SNAPSHOT"
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
maven { url = uri("KOTLIN_REPO") }
|
||||
}
|
||||
|
||||
+1
@@ -17,6 +17,7 @@ version = '1.0-SNAPSHOT'
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
maven { url 'KOTLIN_REPO' }
|
||||
}
|
||||
|
||||
+1
@@ -17,6 +17,7 @@ version = "1.0-SNAPSHOT"
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
maven { url = uri("KOTLIN_REPO") }
|
||||
}
|
||||
|
||||
+4
@@ -150,6 +150,10 @@ project.template.mpp.mobile.lib.description=Library that supports sharing code b
|
||||
module.template.console.jvm.title=Console Application
|
||||
module.template.console.jvm.description=Simple "Hello World!" Kotlin/JVM application that works in the console
|
||||
|
||||
module.template.mpp.mobile.title=Mobile Application
|
||||
module.template.mpp.mobile.description=Mobile applications for iOS and Android with Kotlin Multiplatform Mobile, which supports sharing common code between platforms.
|
||||
|
||||
|
||||
module.template.ktor.server.title=Ktor server
|
||||
module.template.ktor.server.description=Configurable Ktor web server for building web applications
|
||||
module.template.ktor.server.setting.engine=Ktor server engine
|
||||
|
||||
+9
@@ -10,6 +10,10 @@ import org.jetbrains.kotlin.tools.projectWizard.core.service.ServicesManager
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.service.SettingSavingWizardService
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.service.WizardService
|
||||
import org.jetbrains.kotlin.tools.projectWizard.phases.GenerationPhase
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.buildSystem.allIRModules
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.Module
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.ModuleReference
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.path
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
|
||||
@@ -239,6 +243,11 @@ fun Reader.getUnspecifiedSettings(phases: Set<GenerationPhase>): List<AnySetting
|
||||
val provided = pluginSettings.map(PluginSetting<*, *>::path).toSet()
|
||||
return required.filterNot { it.path in provided }
|
||||
}
|
||||
fun Reader.moduleByReference(reference: ModuleReference): Module = when (reference) {
|
||||
is ModuleReference.ByModule -> reference.module
|
||||
is ModuleReference.ByPath -> allIRModules.first { it.originalModule.path == reference.path }.originalModule
|
||||
}
|
||||
|
||||
|
||||
|
||||
typealias Reader = Context.Reader
|
||||
|
||||
+3
@@ -12,6 +12,9 @@ import kotlin.reflect.KProperty
|
||||
inline infix fun <A, B, C> ((A) -> B).andThen(crossinline then: (B) -> C): (A) -> C =
|
||||
{ then(this(it)) }
|
||||
|
||||
inline fun <A, B, C> compose(crossinline function: (A) -> B, crossinline then: (B) -> C): (A) -> C =
|
||||
{ then(function(it)) }
|
||||
|
||||
|
||||
/**
|
||||
* Composes two function together like normal composition if first function returns non-null value;
|
||||
|
||||
+10
@@ -138,6 +138,7 @@ sealed class ModulesStructureIR : BuildSystemIR, IrsOwner {
|
||||
|
||||
data class MultiplatformModulesStructureIR(
|
||||
val targets: List<BuildSystemIR>,
|
||||
val multiplatformModule: FakeMultiplatformModuleIR,
|
||||
override val modules: List<MultiplatformModuleIR>,
|
||||
override val irs: PersistentList<BuildSystemIR>
|
||||
) : GradleIR, ModulesStructureIR() {
|
||||
@@ -173,6 +174,15 @@ fun MultiplatformModulesStructureIR.updateTargets(
|
||||
return copy(targets = newTargets)
|
||||
}
|
||||
|
||||
fun MultiplatformModulesStructureIR.updateSourceSets(
|
||||
updater: (ModuleIR) -> ModuleIR
|
||||
): MultiplatformModulesStructureIR {
|
||||
val newModules = modules.map { updater(it) as MultiplatformModuleIR }
|
||||
return copy(modules = newModules)
|
||||
}
|
||||
|
||||
|
||||
|
||||
data class SingleplatformModulesStructureWithSingleModuleIR(
|
||||
val module: SingleplatformModuleIR,
|
||||
override val irs: PersistentList<BuildSystemIR>
|
||||
|
||||
+5
@@ -16,6 +16,11 @@ fun <I : IrsOwner> I.withIrs(irs: List<BuildSystemIR>) = withReplacedIrs(irs = t
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <I : IrsOwner> I.withIrs(vararg irs: BuildSystemIR) = withReplacedIrs(irs = this.irs + irs) as I
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
inline fun <I : IrsOwner> I.withoutIrs(filterNot: (BuildSystemIR) -> Boolean): I =
|
||||
withReplacedIrs(irs = this.irs.filterNot(filterNot).toPersistentList()) as I
|
||||
|
||||
|
||||
|
||||
inline fun <reified I : BuildSystemIR> IrsOwner.irsOfType(): List<I> =
|
||||
irs.filterIsInstance<I>().let { irs ->
|
||||
|
||||
+19
@@ -1,6 +1,7 @@
|
||||
package org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem
|
||||
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle.GradleIR
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.printer.BuildFilePrinter
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.printer.GradlePrinter
|
||||
@@ -16,8 +17,26 @@ sealed class ModuleIR : IrsOwner, BuildSystemIR {
|
||||
abstract val template: Template?
|
||||
abstract val originalModule: Module
|
||||
abstract val sourcesets: List<SourcesetIR>
|
||||
|
||||
abstract override fun withReplacedIrs(irs: PersistentList<BuildSystemIR>): ModuleIR
|
||||
}
|
||||
|
||||
data class FakeMultiplatformModuleIR(
|
||||
override val name: String,
|
||||
override val path: Path,
|
||||
override val template: Template?,
|
||||
val targets: List<MultiplatformModuleIR>,
|
||||
override val originalModule: Module
|
||||
) : ModuleIR() {
|
||||
override val sourcesets: List<SourcesetIR> = emptyList()
|
||||
override val irs: PersistentList<BuildSystemIR> = persistentListOf()
|
||||
|
||||
override fun withReplacedIrs(irs: PersistentList<BuildSystemIR>): FakeMultiplatformModuleIR = this
|
||||
|
||||
override fun BuildFilePrinter.render() {
|
||||
error("Should not be called")
|
||||
}
|
||||
}
|
||||
|
||||
data class SingleplatformModuleIR(
|
||||
override val name: String,
|
||||
|
||||
+1
@@ -66,6 +66,7 @@ object AndroidSinglePlatformModuleConfigurator :
|
||||
|
||||
override fun createBuildFileIRs(reader: Reader, configurationData: ModulesToIrConversionData, module: Module) = irsList {
|
||||
+super<AndroidModuleConfigurator>.createBuildFileIRs(reader, configurationData, module)
|
||||
+RepositoryIR((DefaultRepository.JCENTER))
|
||||
+AndroidConfigIR(
|
||||
javaPackage = when (reader.createAndroidPlugin(module)) {
|
||||
AndroidGradlePlugin.APPLICATION -> module.javaPackage(configurationData.pomIr)
|
||||
|
||||
+4
-309
@@ -7,31 +7,20 @@ package org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators
|
||||
|
||||
import org.jetbrains.annotations.NonNls
|
||||
import org.jetbrains.kotlin.tools.projectWizard.KotlinNewProjectWizardBundle
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.*
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.entity.properties.ModuleConfiguratorProperty
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.entity.settings.ModuleConfiguratorSetting
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.TaskResult
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.Writer
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.compute
|
||||
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.KotlinBuildSystemPluginIR
|
||||
import org.jetbrains.kotlin.tools.projectWizard.phases.GenerationPhase
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.buildSystem.gradle.GradlePlugin
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.KotlinPlugin
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ModuleSubType
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ModulesToIrConversionData
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.projectPath
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.templates.TemplatesPlugin
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.JavaPackage
|
||||
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.SourcesetType
|
||||
import org.jetbrains.kotlin.tools.projectWizard.templates.FileDescriptor
|
||||
import org.jetbrains.kotlin.tools.projectWizard.templates.FileTemplate
|
||||
import org.jetbrains.kotlin.tools.projectWizard.templates.FileTextDescriptor
|
||||
import java.nio.file.Path
|
||||
|
||||
object MppModuleConfigurator : ModuleConfigurator,
|
||||
ModuleConfiguratorWithSettings,
|
||||
ModuleConfiguratorSettings(),
|
||||
ModuleConfiguratorProperties,
|
||||
ModuleConfiguratorWithProperties {
|
||||
ModuleConfiguratorSettings() {
|
||||
|
||||
override val moduleKind = ModuleKind.multiplatform
|
||||
|
||||
@@ -49,11 +38,6 @@ object MppModuleConfigurator : ModuleConfigurator,
|
||||
version = configurationData.kotlinVersion
|
||||
)
|
||||
|
||||
val mppSources by listProperty<MppSources>()
|
||||
|
||||
override fun getConfiguratorProperties(): List<ModuleConfiguratorProperty<*>> =
|
||||
listOf(mppSources)
|
||||
|
||||
// TODO remove when be removed in KMM wizard
|
||||
val generateTests by booleanSetting("Generate Tests", GenerationPhase.PROJECT_GENERATION) {
|
||||
defaultValue = value(false)
|
||||
@@ -64,295 +48,6 @@ object MppModuleConfigurator : ModuleConfigurator,
|
||||
module: Module,
|
||||
modulePath: Path,
|
||||
): TaskResult<Unit> = compute {
|
||||
createMppFiles(module, modulePath).ensure()
|
||||
createSimpleFiles(module, modulePath).ensure()
|
||||
GradlePlugin.gradleProperties.addValues("kotlin.mpp.enableGranularSourceSetsMetadata" to true)
|
||||
}
|
||||
|
||||
private fun Writer.createMppFiles(
|
||||
module: Module,
|
||||
modulePath: Path
|
||||
): TaskResult<Unit> = inContextOfModuleConfigurator(module) {
|
||||
val mppFiles = mppSources.reference.propertyValue.flatMap { it.mppFiles }
|
||||
.distinctBy { it.fileNameWithPackage } // todo merge files with the same name here
|
||||
mppFiles.mapSequenceIgnore { file ->
|
||||
module.subModules.mapSequenceIgnore mapTargets@{ target ->
|
||||
val moduleSubType = //TODO handle for non-simple target configurator
|
||||
target.configurator.safeAs<SimpleTargetConfigurator>()?.moduleSubType ?: return@mapTargets UNIT_SUCCESS
|
||||
val path = pathForFileInTarget(modulePath, module, file.javaPackage, file.filename, target, SourcesetType.main)
|
||||
val fileTemplate = FileTemplate(
|
||||
FileTextDescriptor(file.printForModuleSubType(moduleSubType), path),
|
||||
projectPath,
|
||||
)
|
||||
TemplatesPlugin.fileTemplatesToRender.addValues(fileTemplate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Writer.createSimpleFiles(
|
||||
module: Module,
|
||||
modulePath: Path
|
||||
): TaskResult<Unit> = inContextOfModuleConfigurator(module) {
|
||||
val mppFiles = mppSources.reference.propertyValue
|
||||
val filesWithPaths = module.subModules.flatMap { target ->
|
||||
val moduleSubType = //TODO handle for non-simple target configurator
|
||||
target.configurator.safeAs<SimpleTargetConfigurator>()?.moduleSubType ?: return@flatMap emptyList()
|
||||
mppFiles
|
||||
.flatMap { it.getFilesFor(moduleSubType) }
|
||||
.distinctBy { it.uniqueIdentifier }
|
||||
.map { file ->
|
||||
val path = projectPath / pathForFileInTarget(modulePath, module, file.javaPackage, file.filename, target, file.type)
|
||||
file to path
|
||||
}
|
||||
}.distinctBy { (_, path) -> path }
|
||||
filesWithPaths.mapSequenceIgnore { (file, path) ->
|
||||
val fileTemplate = FileTemplate(file.fileDescriptor, path, mapOf("package" to file.javaPackage?.asCodePackage()))
|
||||
TemplatesPlugin.fileTemplatesToRender.addValues(fileTemplate)
|
||||
}
|
||||
}
|
||||
|
||||
private fun pathForFileInTarget(
|
||||
mppModulePath: Path,
|
||||
mppModule: Module,
|
||||
javaPackage: JavaPackage?,
|
||||
filename: String,
|
||||
target: Module,
|
||||
sourcesetType: SourcesetType,
|
||||
) = mppModulePath /
|
||||
Defaults.SRC_DIR /
|
||||
"${target.name}${sourcesetType.name.capitalize()}" /
|
||||
mppModule.configurator.kotlinDirectoryName /
|
||||
javaPackage?.asPath() /
|
||||
filename
|
||||
}
|
||||
|
||||
|
||||
@DslMarker
|
||||
annotation class ExpectFileDSL
|
||||
|
||||
data class MppFile(
|
||||
@NonNls val filename: String,
|
||||
@NonNls val javaPackage: JavaPackage? = null,
|
||||
val declarations: List<MppDeclaration>
|
||||
) {
|
||||
|
||||
val fileNameWithPackage
|
||||
get() = javaPackage?.let { "${it.asCodePackage()}." }.orEmpty() + filename
|
||||
|
||||
fun printForModuleSubType(moduleSubType: ModuleSubType): String = buildString {
|
||||
javaPackage?.let { appendLine("package ${it.asCodePackage()}"); appendLine() }
|
||||
if (moduleSubType == ModuleSubType.common) {
|
||||
declarations.joinTo(this, separator = "\n\n") { it.printExpect() }
|
||||
} else {
|
||||
printImports(declarations.flatMap { it.importsFor(moduleSubType) })
|
||||
declarations.joinTo(this, separator = "\n\n") { it.printActualFor(moduleSubType) }
|
||||
}
|
||||
}.trim()
|
||||
|
||||
private fun StringBuilder.printImports(imports: List<String>) {
|
||||
if (imports.isEmpty()) return
|
||||
imports.distinct().joinTo(this, separator = "\n", prefix = "\n", postfix = "\n\n") { import ->
|
||||
"import $import"
|
||||
}
|
||||
}
|
||||
|
||||
@ExpectFileDSL
|
||||
class Builder(private val filename: String, val javaPackage: JavaPackage? = null) {
|
||||
private val declarations = mutableListOf<MppDeclaration>()
|
||||
|
||||
fun function(signature: String, init: MppFunction.Builder.() -> Unit = {}) {
|
||||
declarations += MppFunction.Builder(signature).apply(init).build()
|
||||
}
|
||||
|
||||
fun `class`(name: String, init: MppClass.Builder.() -> Unit = {}) {
|
||||
declarations += MppClass.Builder(name).apply(init).build()
|
||||
}
|
||||
|
||||
fun build() = MppFile(filename, javaPackage, declarations)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ExpectFileDSL
|
||||
class MppSources(val mppFiles: List<MppFile>, val simpleFiles: List<SimpleFiles>) {
|
||||
|
||||
fun getFilesFor(moduleSubType: ModuleSubType): List<SimpleFile> =
|
||||
simpleFiles.filter { moduleSubType in it.moduleSubTypes }.flatMap { it.files }
|
||||
|
||||
class Builder(val javaPackage: JavaPackage?) {
|
||||
private val mppFiles = mutableListOf<MppFile>()
|
||||
private val simpleFiles = mutableListOf<SimpleFiles>()
|
||||
|
||||
fun mppFile(filename: String, init: MppFile.Builder.() -> Unit) {
|
||||
mppFiles += MppFile.Builder(filename, javaPackage).apply(init).build()
|
||||
}
|
||||
|
||||
fun filesFor(vararg moduleSubTypes: ModuleSubType, init: SimpleFiles.Builder.() -> Unit) {
|
||||
simpleFiles += SimpleFiles.Builder(moduleSubTypes.toList(), javaPackage).apply(init).build()
|
||||
}
|
||||
|
||||
fun build() = MppSources(mppFiles, simpleFiles)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
data class SimpleFiles(val moduleSubTypes: List<ModuleSubType>, val files: List<SimpleFile>) {
|
||||
class Builder(private val moduleSubTypes: List<ModuleSubType>, val filesPackage: JavaPackage?) {
|
||||
private val files = mutableListOf<SimpleFile>()
|
||||
|
||||
fun file(fileDescriptor: FileDescriptor, filename: String, type: SourcesetType, init: SimpleFile.Builder.() -> Unit = {}) {
|
||||
files += SimpleFile.Builder(fileDescriptor, filename, type).apply(init).apply {
|
||||
javaPackage = filesPackage
|
||||
}.build()
|
||||
}
|
||||
|
||||
fun build() = SimpleFiles(moduleSubTypes, files)
|
||||
}
|
||||
}
|
||||
|
||||
data class SimpleFile(val fileDescriptor: FileDescriptor, val javaPackage: JavaPackage?, val filename: String, val type: SourcesetType) {
|
||||
val uniqueIdentifier get() = "${type}/${javaPackage}/${filename}"
|
||||
|
||||
class Builder(private val fileDescriptor: FileDescriptor, private val filename: String, private val type: SourcesetType) {
|
||||
var javaPackage: JavaPackage? = null
|
||||
|
||||
fun build() = SimpleFile(fileDescriptor, javaPackage, filename, type)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun mppSources(javaPackage: JavaPackage? = null, init: MppSources.Builder.() -> Unit): MppSources =
|
||||
MppSources.Builder(javaPackage).apply(init).build()
|
||||
|
||||
sealed class MppDeclaration {
|
||||
@Suppress("SpellCheckingInspection")
|
||||
abstract val actuals: Actuals
|
||||
|
||||
abstract fun printExpect(): String
|
||||
|
||||
abstract fun printActualFor(moduleSubType: ModuleSubType): String
|
||||
|
||||
fun importsFor(moduleSubType: ModuleSubType): List<String> = actuals.getBodyFor(moduleSubType).imports
|
||||
|
||||
@ExpectFileDSL
|
||||
abstract class Builder {
|
||||
private var defaultActualDeclarationBody = DefaultActualDeclarationBody(text = "", imports = emptyList())
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
private val actuals = mutableMapOf<ModuleSubType, ActualDeclarationBody>()
|
||||
|
||||
fun default(defaultText: String, init: DefaultActualDeclarationBody.Builder.() -> Unit = {}) {
|
||||
defaultActualDeclarationBody = DefaultActualDeclarationBody.Builder(defaultText).also(init).build()
|
||||
}
|
||||
|
||||
fun actualFor(vararg moduleSubTypes: ModuleSubType, actualBody: String, init: ActualDeclarationBody.Builder.() -> Unit = {}) {
|
||||
moduleSubTypes.forEach { moduleSubType ->
|
||||
actuals[moduleSubType] = ActualDeclarationBody.Builder(actualBody).apply(init).build()
|
||||
}
|
||||
}
|
||||
|
||||
protected fun buildActuals() = Actuals(defaultActualDeclarationBody, actuals)
|
||||
}
|
||||
}
|
||||
|
||||
data class MppFunction(
|
||||
val signature: String,
|
||||
@Suppress("SpellCheckingInspection")
|
||||
override val actuals: Actuals,
|
||||
) : MppDeclaration() {
|
||||
override fun printExpect(): String =
|
||||
"expect fun $signature"
|
||||
|
||||
override fun printActualFor(moduleSubType: ModuleSubType): String {
|
||||
val body = actuals.getBodyFor(moduleSubType)
|
||||
return buildString {
|
||||
appendLine("actual fun $signature {")
|
||||
appendLine(body.text.indented(4))
|
||||
append("}")
|
||||
}
|
||||
}
|
||||
|
||||
@ExpectFileDSL
|
||||
class Builder(private val signature: String) : MppDeclaration.Builder() {
|
||||
fun build(): MppFunction = MppFunction(
|
||||
signature,
|
||||
buildActuals(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class MppClass(
|
||||
val name: String,
|
||||
val expectBody: String?,
|
||||
@Suppress("SpellCheckingInspection")
|
||||
override val actuals: Actuals,
|
||||
) : MppDeclaration() {
|
||||
override fun printExpect(): String = buildString {
|
||||
append("expect class $name()")
|
||||
expectBody?.let { body ->
|
||||
appendLine(" {")
|
||||
appendLine(body.indented(4))
|
||||
append("}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun printActualFor(moduleSubType: ModuleSubType): String {
|
||||
val body = actuals.getBodyFor(moduleSubType)
|
||||
return buildString {
|
||||
appendLine("actual class $name actual constructor() {")
|
||||
appendLine(body.text.indented(4))
|
||||
append("}")
|
||||
}
|
||||
}
|
||||
|
||||
@ExpectFileDSL
|
||||
class Builder(private val name: String) : MppDeclaration.Builder() {
|
||||
var expectBody: String? = null
|
||||
|
||||
fun build(): MppClass = MppClass(
|
||||
name,
|
||||
expectBody,
|
||||
buildActuals(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun String.indented(indentValue: Int): String {
|
||||
val indent = " ".repeat(indentValue)
|
||||
return split('\n').joinToString(separator = "\n") { line -> indent + line.trim() }
|
||||
}
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
data class Actuals(
|
||||
val defaultActualDeclarationBody: DefaultActualDeclarationBody,
|
||||
val actuals: Map<ModuleSubType, ActualDeclarationBody>,
|
||||
) {
|
||||
fun getBodyFor(moduleSubType: ModuleSubType): DeclarationBody =
|
||||
actuals[moduleSubType] ?: defaultActualDeclarationBody
|
||||
}
|
||||
|
||||
sealed class DeclarationBody {
|
||||
abstract val text: String
|
||||
abstract val imports: List<String>
|
||||
|
||||
abstract class Builder {
|
||||
protected val imports = mutableListOf<String>()
|
||||
|
||||
fun import(import: String) {
|
||||
imports += import
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class ActualDeclarationBody(override val text: String, override val imports: List<String>) : DeclarationBody() {
|
||||
class Builder(private val text: String) : DeclarationBody.Builder() {
|
||||
fun build() = ActualDeclarationBody(text, imports)
|
||||
}
|
||||
}
|
||||
|
||||
data class DefaultActualDeclarationBody(override val text: String, override val imports: List<String>) : DeclarationBody() {
|
||||
class Builder(private val text: String) : DeclarationBody.Builder() {
|
||||
fun build() = DefaultActualDeclarationBody(text, imports)
|
||||
}
|
||||
}
|
||||
+327
@@ -0,0 +1,327 @@
|
||||
/*
|
||||
* 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.mpp
|
||||
|
||||
import org.jetbrains.annotations.NonNls
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.*
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.safeAs
|
||||
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.SimpleTargetConfigurator
|
||||
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.inContextOfModuleConfigurator
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.buildSystem.gradle.GradlePlugin
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ModuleSubType
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ModulesToIrConversionData
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.projectPath
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.templates.TemplatesPlugin
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.JavaPackage
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.Module
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.SourcesetType
|
||||
import org.jetbrains.kotlin.tools.projectWizard.templates.FileDescriptor
|
||||
import org.jetbrains.kotlin.tools.projectWizard.templates.FileTemplate
|
||||
import org.jetbrains.kotlin.tools.projectWizard.templates.FileTextDescriptor
|
||||
import java.nio.file.Path
|
||||
|
||||
@DslMarker
|
||||
annotation class ExpectFileDSL
|
||||
|
||||
data class MppFile(
|
||||
@NonNls val filename: String,
|
||||
@NonNls val javaPackage: JavaPackage? = null,
|
||||
val declarations: List<MppDeclaration>
|
||||
) {
|
||||
|
||||
val fileNameWithPackage
|
||||
get() = javaPackage?.let { "${it.asCodePackage()}." }.orEmpty() + filename
|
||||
|
||||
fun printForModuleSubType(moduleSubType: ModuleSubType): String = buildString {
|
||||
javaPackage?.let { appendLine("package ${it.asCodePackage()}"); appendLine() }
|
||||
if (moduleSubType == ModuleSubType.common) {
|
||||
declarations.joinTo(this, separator = "\n\n") { it.printExpect() }
|
||||
} else {
|
||||
printImports(declarations.flatMap { it.importsFor(moduleSubType) })
|
||||
declarations.joinTo(this, separator = "\n\n") { it.printActualFor(moduleSubType) }
|
||||
}
|
||||
}.trim()
|
||||
|
||||
private fun StringBuilder.printImports(imports: List<String>) {
|
||||
if (imports.isEmpty()) return
|
||||
imports.distinct().joinTo(this, separator = "\n", prefix = "\n", postfix = "\n\n") { import ->
|
||||
"import $import"
|
||||
}
|
||||
}
|
||||
|
||||
@ExpectFileDSL
|
||||
class Builder(private val filename: String, val javaPackage: JavaPackage? = null) {
|
||||
private val declarations = mutableListOf<MppDeclaration>()
|
||||
|
||||
fun function(signature: String, init: MppFunction.Builder.() -> Unit = {}) {
|
||||
declarations += MppFunction.Builder(signature).apply(init).build()
|
||||
}
|
||||
|
||||
fun `class`(name: String, init: MppClass.Builder.() -> Unit = {}) {
|
||||
declarations += MppClass.Builder(name).apply(init).build()
|
||||
}
|
||||
|
||||
fun build() = MppFile(filename, javaPackage, declarations)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ExpectFileDSL
|
||||
class MppSources(val mppFiles: List<MppFile>, val simpleFiles: List<SimpleFiles>) {
|
||||
|
||||
fun getFilesFor(moduleSubType: ModuleSubType): List<SimpleFile> =
|
||||
simpleFiles.filter { moduleSubType in it.moduleSubTypes }.flatMap { it.files }
|
||||
|
||||
class Builder(val javaPackage: JavaPackage?) {
|
||||
private val mppFiles = mutableListOf<MppFile>()
|
||||
private val simpleFiles = mutableListOf<SimpleFiles>()
|
||||
|
||||
fun mppFile(filename: String, init: MppFile.Builder.() -> Unit) {
|
||||
mppFiles += MppFile.Builder(filename, javaPackage).apply(init).build()
|
||||
}
|
||||
|
||||
fun filesFor(vararg moduleSubTypes: ModuleSubType, init: SimpleFiles.Builder.() -> Unit) {
|
||||
simpleFiles += SimpleFiles.Builder(moduleSubTypes.toList(), javaPackage).apply(init).build()
|
||||
}
|
||||
|
||||
fun build() = MppSources(mppFiles, simpleFiles)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
data class SimpleFiles(val moduleSubTypes: List<ModuleSubType>, val files: List<SimpleFile>) {
|
||||
class Builder(private val moduleSubTypes: List<ModuleSubType>, val filesPackage: JavaPackage?) {
|
||||
private val files = mutableListOf<SimpleFile>()
|
||||
|
||||
fun file(fileDescriptor: FileDescriptor, filename: String, type: SourcesetType, init: SimpleFile.Builder.() -> Unit = {}) {
|
||||
files += SimpleFile.Builder(fileDescriptor, filename, type).apply(init).apply {
|
||||
javaPackage = filesPackage
|
||||
}.build()
|
||||
}
|
||||
|
||||
fun build() = SimpleFiles(moduleSubTypes, files)
|
||||
}
|
||||
}
|
||||
|
||||
data class SimpleFile(val fileDescriptor: FileDescriptor, val javaPackage: JavaPackage?, val filename: String, val type: SourcesetType) {
|
||||
val uniqueIdentifier get() = "${type}/${javaPackage}/${filename}"
|
||||
|
||||
class Builder(private val fileDescriptor: FileDescriptor, private val filename: String, private val type: SourcesetType) {
|
||||
var javaPackage: JavaPackage? = null
|
||||
|
||||
fun build() = SimpleFile(fileDescriptor, javaPackage, filename, type)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun mppSources(javaPackage: JavaPackage? = null, init: MppSources.Builder.() -> Unit): MppSources =
|
||||
MppSources.Builder(javaPackage).apply(init).build()
|
||||
|
||||
sealed class MppDeclaration {
|
||||
@Suppress("SpellCheckingInspection")
|
||||
abstract val actuals: Actuals
|
||||
|
||||
abstract fun printExpect(): String
|
||||
|
||||
abstract fun printActualFor(moduleSubType: ModuleSubType): String
|
||||
|
||||
fun importsFor(moduleSubType: ModuleSubType): List<String> = actuals.getBodyFor(moduleSubType).imports
|
||||
|
||||
@ExpectFileDSL
|
||||
abstract class Builder {
|
||||
private var defaultActualDeclarationBody = DefaultActualDeclarationBody(text = "", imports = emptyList())
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
private val actuals = mutableMapOf<ModuleSubType, ActualDeclarationBody>()
|
||||
|
||||
fun default(defaultText: String, init: DefaultActualDeclarationBody.Builder.() -> Unit = {}) {
|
||||
defaultActualDeclarationBody = DefaultActualDeclarationBody.Builder(defaultText).also(init).build()
|
||||
}
|
||||
|
||||
fun actualFor(vararg moduleSubTypes: ModuleSubType, actualBody: String, init: ActualDeclarationBody.Builder.() -> Unit = {}) {
|
||||
moduleSubTypes.forEach { moduleSubType ->
|
||||
actuals[moduleSubType] = ActualDeclarationBody.Builder(actualBody).apply(init).build()
|
||||
}
|
||||
}
|
||||
|
||||
protected fun buildActuals() = Actuals(defaultActualDeclarationBody, actuals)
|
||||
}
|
||||
}
|
||||
|
||||
data class MppFunction(
|
||||
val signature: String,
|
||||
@Suppress("SpellCheckingInspection")
|
||||
override val actuals: Actuals,
|
||||
) : MppDeclaration() {
|
||||
override fun printExpect(): String =
|
||||
"expect fun $signature"
|
||||
|
||||
override fun printActualFor(moduleSubType: ModuleSubType): String {
|
||||
val body = actuals.getBodyFor(moduleSubType)
|
||||
return buildString {
|
||||
appendLine("actual fun $signature {")
|
||||
appendLine(body.text.indented(4))
|
||||
append("}")
|
||||
}
|
||||
}
|
||||
|
||||
@ExpectFileDSL
|
||||
class Builder(private val signature: String) : MppDeclaration.Builder() {
|
||||
fun build(): MppFunction = MppFunction(
|
||||
signature,
|
||||
buildActuals(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class MppClass(
|
||||
val name: String,
|
||||
val expectBody: String?,
|
||||
@Suppress("SpellCheckingInspection")
|
||||
override val actuals: Actuals,
|
||||
) : MppDeclaration() {
|
||||
override fun printExpect(): String = buildString {
|
||||
append("expect class $name()")
|
||||
expectBody?.let { body ->
|
||||
appendLine(" {")
|
||||
appendLine(body.indented(4))
|
||||
append("}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun printActualFor(moduleSubType: ModuleSubType): String {
|
||||
val body = actuals.getBodyFor(moduleSubType)
|
||||
return buildString {
|
||||
appendLine("actual class $name actual constructor() {")
|
||||
appendLine(body.text.indented(4))
|
||||
append("}")
|
||||
}
|
||||
}
|
||||
|
||||
@ExpectFileDSL
|
||||
class Builder(private val name: String) : MppDeclaration.Builder() {
|
||||
var expectBody: String? = null
|
||||
|
||||
fun build(): MppClass = MppClass(
|
||||
name,
|
||||
expectBody,
|
||||
buildActuals(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun String.indented(indentValue: Int): String {
|
||||
val indent = " ".repeat(indentValue)
|
||||
return split('\n').joinToString(separator = "\n") { line -> indent + line.trim() }
|
||||
}
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
data class Actuals(
|
||||
val defaultActualDeclarationBody: DefaultActualDeclarationBody,
|
||||
val actuals: Map<ModuleSubType, ActualDeclarationBody>,
|
||||
) {
|
||||
fun getBodyFor(moduleSubType: ModuleSubType): DeclarationBody =
|
||||
actuals[moduleSubType] ?: defaultActualDeclarationBody
|
||||
}
|
||||
|
||||
sealed class DeclarationBody {
|
||||
abstract val text: String
|
||||
abstract val imports: List<String>
|
||||
|
||||
abstract class Builder {
|
||||
protected val imports = mutableListOf<String>()
|
||||
|
||||
fun import(import: String) {
|
||||
imports += import
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class ActualDeclarationBody(override val text: String, override val imports: List<String>) : DeclarationBody() {
|
||||
class Builder(private val text: String) : DeclarationBody.Builder() {
|
||||
fun build() = ActualDeclarationBody(text, imports)
|
||||
}
|
||||
}
|
||||
|
||||
data class DefaultActualDeclarationBody(override val text: String, override val imports: List<String>) : DeclarationBody() {
|
||||
class Builder(private val text: String) : DeclarationBody.Builder() {
|
||||
fun build() = DefaultActualDeclarationBody(text, imports)
|
||||
}
|
||||
}
|
||||
|
||||
fun Writer.applyMppStructure(
|
||||
mppSources: List<MppSources>,
|
||||
module: Module,
|
||||
modulePath: Path,
|
||||
): TaskResult<Unit> = compute {
|
||||
createMppFiles(mppSources, module, modulePath).ensure()
|
||||
createSimpleFiles(mppSources, module, modulePath).ensure()
|
||||
}
|
||||
|
||||
fun Writer.applyMppStructure(
|
||||
mppSources: MppSources,
|
||||
module: Module,
|
||||
modulePath: Path,
|
||||
): TaskResult<Unit> = applyMppStructure(listOf(mppSources), module, modulePath)
|
||||
|
||||
private fun Writer.createMppFiles(
|
||||
mppSources: List<MppSources>,
|
||||
module: Module,
|
||||
modulePath: Path
|
||||
): TaskResult<Unit> = inContextOfModuleConfigurator(module) {
|
||||
val mppFiles = mppSources.flatMap { it.mppFiles }
|
||||
.distinctBy { it.fileNameWithPackage } // todo merge files with the same name here
|
||||
mppFiles.mapSequenceIgnore { file ->
|
||||
module.subModules.mapSequenceIgnore mapTargets@{ target ->
|
||||
val moduleSubType = //TODO handle for non-simple target configurator
|
||||
target.configurator.safeAs<SimpleTargetConfigurator>()?.moduleSubType ?: return@mapTargets UNIT_SUCCESS
|
||||
val path = pathForFileInTarget(modulePath, module, file.javaPackage, file.filename, target, SourcesetType.main)
|
||||
val fileTemplate = FileTemplate(
|
||||
FileTextDescriptor(file.printForModuleSubType(moduleSubType), path),
|
||||
projectPath,
|
||||
)
|
||||
TemplatesPlugin.fileTemplatesToRender.addValues(fileTemplate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Writer.createSimpleFiles(
|
||||
mppSources: List<MppSources>,
|
||||
module: Module,
|
||||
modulePath: Path
|
||||
): TaskResult<Unit> = inContextOfModuleConfigurator(module) {
|
||||
val mppFiles = mppSources
|
||||
val filesWithPaths = module.subModules.flatMap { target ->
|
||||
val moduleSubType = //TODO handle for non-simple target configurator
|
||||
target.configurator.safeAs<SimpleTargetConfigurator>()?.moduleSubType ?: return@flatMap emptyList()
|
||||
mppFiles
|
||||
.flatMap { it.getFilesFor(moduleSubType) }
|
||||
.distinctBy { it.uniqueIdentifier }
|
||||
.map { file ->
|
||||
val path = projectPath / pathForFileInTarget(modulePath, module, file.javaPackage, file.filename, target, file.type)
|
||||
file to path
|
||||
}
|
||||
}.distinctBy { (_, path) -> path }
|
||||
filesWithPaths.mapSequenceIgnore { (file, path) ->
|
||||
val fileTemplate = FileTemplate(file.fileDescriptor, path, mapOf("package" to file.javaPackage?.asCodePackage()))
|
||||
TemplatesPlugin.fileTemplatesToRender.addValues(fileTemplate)
|
||||
}
|
||||
}
|
||||
|
||||
private fun pathForFileInTarget(
|
||||
mppModulePath: Path,
|
||||
mppModule: Module,
|
||||
javaPackage: JavaPackage?,
|
||||
filename: String,
|
||||
target: Module,
|
||||
sourcesetType: SourcesetType,
|
||||
) = mppModulePath /
|
||||
Defaults.SRC_DIR /
|
||||
"${target.name}${sourcesetType.name.capitalize()}" /
|
||||
mppModule.configurator.kotlinDirectoryName /
|
||||
javaPackage?.asPath() /
|
||||
filename
|
||||
+2
-1
@@ -32,7 +32,8 @@ object Plugins {
|
||||
JsTemplatesPlugin(context),
|
||||
ReactJsTemplatesPlugin(context),
|
||||
SimpleNodeJsTemplatesPlugin(context),
|
||||
NativeConsoleApplicationTemplatePlugin(context)
|
||||
NativeConsoleApplicationTemplatePlugin(context),
|
||||
MobileMppTemplatePlugin(context),
|
||||
)
|
||||
}
|
||||
}
|
||||
+7
@@ -230,6 +230,13 @@ class ModulesToIRsConverter(
|
||||
modulePath,
|
||||
MultiplatformModulesStructureIR(
|
||||
targetIrs,
|
||||
FakeMultiplatformModuleIR(
|
||||
module.name,
|
||||
modulePath,
|
||||
module.template,
|
||||
targetModuleIrs,
|
||||
module,
|
||||
),
|
||||
targetModuleIrs,
|
||||
persistentListOf()
|
||||
),
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package org.jetbrains.kotlin.tools.projectWizard.plugins.templates
|
||||
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.Context
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.PluginSettingsOwner
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.entity.PipelineTask
|
||||
import org.jetbrains.kotlin.tools.projectWizard.phases.GenerationPhase
|
||||
import org.jetbrains.kotlin.tools.projectWizard.templates.mpp.MobileMppTemplate
|
||||
|
||||
class MobileMppTemplatePlugin(context: Context) : TemplatePlugin(context) {
|
||||
override val path = pluginPath
|
||||
|
||||
override val pipelineTasks: List<PipelineTask> = super.pipelineTasks +
|
||||
listOf(
|
||||
addTemplate,
|
||||
)
|
||||
|
||||
companion object : PluginSettingsOwner() {
|
||||
override val pluginPath = "template.mobile.mpp"
|
||||
|
||||
val addTemplate by pipelineTask(GenerationPhase.PREPARE) {
|
||||
withAction {
|
||||
TemplatesPlugin.addTemplate.execute(MobileMppTemplate())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+17
-4
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.tools.projectWizard.core.entity.settings.PluginSetti
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.service.TemplateEngineService
|
||||
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.*
|
||||
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.ModuleConfiguratorWithTests
|
||||
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.MppModuleConfigurator.runArbitraryTask
|
||||
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.isPresent
|
||||
import org.jetbrains.kotlin.tools.projectWizard.phases.GenerationPhase
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.buildSystem.BuildSystemPlugin
|
||||
@@ -67,20 +68,31 @@ class TemplatesPlugin(context: Context) : Plugin(context) {
|
||||
|
||||
withAction {
|
||||
updateBuildFiles { buildFile ->
|
||||
buildFile.modules.modules.mapSequence { module ->
|
||||
val moduleStructure = buildFile.modules
|
||||
val moduleIRs = buildList<ModuleIR> {
|
||||
if (moduleStructure is MultiplatformModulesStructureIR) {
|
||||
+moduleStructure.multiplatformModule
|
||||
}
|
||||
+moduleStructure.modules
|
||||
}
|
||||
moduleIRs.mapSequence { module ->
|
||||
applyTemplateToModule(
|
||||
module.template,
|
||||
module
|
||||
).map { result -> module.withIrs(result.librariesToAdd) to result }
|
||||
).map { result -> result.updateModuleIR(module.withIrs(result.librariesToAdd)) to result }
|
||||
}.map {
|
||||
val (moduleIrs, results) = it.unzip()
|
||||
val foldedResults = results.fold()
|
||||
buildFile.copy(
|
||||
modules = buildFile.modules.withModules(moduleIrs)
|
||||
modules = buildFile.modules.withModules(moduleIrs.filterNot { it is FakeMultiplatformModuleIR })
|
||||
).withIrs(foldedResults.irsToAddToBuildFile).let { buildFile ->
|
||||
when (val structure = buildFile.modules) {
|
||||
is MultiplatformModulesStructureIR ->
|
||||
buildFile.copy(modules = structure.updateTargets(foldedResults.updateTarget))
|
||||
buildFile.copy(
|
||||
modules = structure
|
||||
.updateTargets(foldedResults.updateTarget)
|
||||
.updateSourceSets(foldedResults.updateModuleIR)
|
||||
)
|
||||
else -> buildFile
|
||||
}
|
||||
}
|
||||
@@ -164,6 +176,7 @@ class TemplatesPlugin(context: Context) : Plugin(context) {
|
||||
}
|
||||
SRC_DIR / "${module.name}${filePath.sourcesetType.name.capitalize()}" / directory
|
||||
}
|
||||
is FakeMultiplatformModuleIR -> error("Not supported for FakeMultiplatformModuleIR")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-5
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ProjectKind
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.DisplayableSettingItem
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.*
|
||||
import org.jetbrains.kotlin.tools.projectWizard.templates.*
|
||||
import org.jetbrains.kotlin.tools.projectWizard.templates.mpp.MobileMppTemplate
|
||||
|
||||
sealed class ProjectTemplate : DisplayableSettingItem {
|
||||
abstract val title: String
|
||||
@@ -165,7 +166,7 @@ object MultiplatformApplicationProjectTemplate : ProjectTemplate() {
|
||||
override val setsPluginSettings: List<SettingWithValue<*, *>>
|
||||
get() = listOf(
|
||||
KotlinPlugin.modules.reference withValue listOf(
|
||||
MultiplatformModule("mainModule", listOf(ModuleType.common.createDefaultTarget()))
|
||||
MultiplatformModule("mainModule", targets = listOf(ModuleType.common.createDefaultTarget()))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -206,7 +207,7 @@ object MultiplatformLibraryProjectTemplate : ProjectTemplate() {
|
||||
KotlinPlugin.modules.reference withValue listOf(
|
||||
MultiplatformModule(
|
||||
"library",
|
||||
listOf(
|
||||
targets = listOf(
|
||||
ModuleType.common.createDefaultTarget(),
|
||||
ModuleType.jvm.createDefaultTarget(),
|
||||
ModuleType.js.createDefaultTarget().withConfiguratorSettings(JsBrowserTargetConfigurator) {
|
||||
@@ -231,7 +232,7 @@ object FullStackWebApplicationProjectTemplate : ProjectTemplate() {
|
||||
KotlinPlugin.modules.reference withValue listOf(
|
||||
MultiplatformModule(
|
||||
"application",
|
||||
listOf(
|
||||
targets = listOf(
|
||||
ModuleType.common.createDefaultTarget(),
|
||||
ModuleType.jvm.createDefaultTarget().apply {
|
||||
withTemplate(KtorServerTemplate()) {
|
||||
@@ -336,7 +337,8 @@ object MultiplatformMobileApplicationProjectTemplate : ProjectTemplate() {
|
||||
override val setsModules: List<Module> = buildList {
|
||||
val shared = MultiplatformModule(
|
||||
"shared",
|
||||
listOf(
|
||||
template = MobileMppTemplate(),
|
||||
targets = listOf(
|
||||
ModuleType.common.createDefaultTarget(),
|
||||
Module(
|
||||
"android",
|
||||
@@ -390,7 +392,7 @@ object MultiplatformMobileLibraryProjectTemplate : ProjectTemplate() {
|
||||
KotlinPlugin.modules.reference withValue listOf(
|
||||
MultiplatformModule(
|
||||
"library",
|
||||
listOf(
|
||||
targets = listOf(
|
||||
ModuleType.common.createDefaultTarget(),
|
||||
Module(
|
||||
"android",
|
||||
|
||||
+2
-2
@@ -185,11 +185,11 @@ fun MultiplatformTargetModule(@NonNls name: String, configurator: ModuleConfigur
|
||||
)
|
||||
|
||||
@Suppress("FunctionName")
|
||||
fun MultiplatformModule(@NonNls name: String, targets: List<Module> = emptyList()) =
|
||||
fun MultiplatformModule(@NonNls name: String, template: Template? = null, targets: List<Module> = emptyList()) =
|
||||
Module(
|
||||
name,
|
||||
MppModuleConfigurator,
|
||||
null,
|
||||
template,
|
||||
emptyList(),
|
||||
targets
|
||||
)
|
||||
|
||||
+9
-48
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.GradleRootProject
|
||||
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.mpp.mppSources
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.buildSystem.isGradle
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ModuleSubType
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ModulesToIrConversionData
|
||||
@@ -78,14 +79,12 @@ sealed class ModuleDependencyType(
|
||||
object AndroidSinglePlatformToMPP : ModuleDependencyType(
|
||||
from = AndroidSinglePlatformModuleConfigurator::class,
|
||||
to = MppModuleConfigurator::class
|
||||
) {
|
||||
override fun Writer.runArbitraryTask(
|
||||
from: Module,
|
||||
to: Module,
|
||||
toModulePath: Path,
|
||||
data: ModulesToIrConversionData
|
||||
): TaskResult<Unit> = addExpectFilesForMppModuleForAndroidAndIos(to, data)
|
||||
}
|
||||
)
|
||||
|
||||
object JVMSinglePlatformToMPP : ModuleDependencyType(
|
||||
from = JvmSinglePlatformModuleConfigurator::class,
|
||||
to = MppModuleConfigurator::class
|
||||
)
|
||||
|
||||
object IOSToMppSinglePlatformToMPP : ModuleDependencyType(
|
||||
from = IOSSinglePlatformModuleConfigurator::class,
|
||||
@@ -100,7 +99,6 @@ sealed class ModuleDependencyType(
|
||||
toModulePath: Path,
|
||||
data: ModulesToIrConversionData
|
||||
): TaskResult<Unit> = compute {
|
||||
addExpectFilesForMppModuleForAndroidAndIos(to, data)
|
||||
inContextOfModuleConfigurator(from) {
|
||||
IOSSinglePlatformModuleConfigurator.dependentModule.reference.update {
|
||||
IOSSinglePlatformModuleConfigurator.DependentModuleReference(to).asSuccess()
|
||||
@@ -113,7 +111,7 @@ sealed class ModuleDependencyType(
|
||||
to: Module,
|
||||
toModulePath: Path,
|
||||
): TaskResult<Unit> {
|
||||
val needDummyFile = inContextOfModuleConfigurator(to) { MppModuleConfigurator.mppSources.reference.propertyValue.isEmpty() }
|
||||
val needDummyFile = false/*TODO*/
|
||||
return if (needDummyFile) {
|
||||
val dummyFilePath =
|
||||
Defaults.SRC_DIR / "${to.iosTargetSafe()!!.name}Main" / to.configurator.kotlinDirectoryName / "dummyFile.kt"
|
||||
@@ -184,6 +182,7 @@ sealed class ModuleDependencyType(
|
||||
companion object {
|
||||
private val ALL = listOf(
|
||||
JVMSinglePlatformToJVMSinglePlatform,
|
||||
JVMSinglePlatformToMPP,
|
||||
AndroidSinglePlatformToMPP,
|
||||
IOSToMppSinglePlatformToMPP
|
||||
)
|
||||
@@ -194,42 +193,4 @@ sealed class ModuleDependencyType(
|
||||
fun isDependencyPossible(from: Module, to: Module): Boolean =
|
||||
getPossibleDependencyType(from, to) != null
|
||||
}
|
||||
}
|
||||
|
||||
private fun Writer.addExpectFilesForMppModuleForAndroidAndIos(mppModule: Module, data: ModulesToIrConversionData): TaskResult<Unit> {
|
||||
val javaPackage = mppModule.javaPackage(data.pomIr)
|
||||
|
||||
val expectFiles = mppSources(javaPackage) {
|
||||
mppFile("Platform.kt") {
|
||||
`class`("Platform") {
|
||||
expectBody = "val platform: String"
|
||||
actualFor(
|
||||
ModuleSubType.android,
|
||||
actualBody = """actual val platform: String = "Android ${'$'}{android.os.Build.VERSION.SDK_INT}""""
|
||||
)
|
||||
|
||||
actualFor(
|
||||
ModuleSubType.iosArm64, ModuleSubType.iosX64, ModuleSubType.ios,
|
||||
actualBody =
|
||||
"""actual val platform: String = UIDevice.currentDevice.systemName() + " " + UIDevice.currentDevice.systemVersion"""
|
||||
) {
|
||||
import("platform.UIKit.UIDevice")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
filesFor(ModuleSubType.common) {
|
||||
file(FileTemplateDescriptor("mppCommon/Greeting.kt.vm", relativePath = null), "Greeting.kt", SourcesetType.main)
|
||||
}
|
||||
|
||||
filesFor(ModuleSubType.android) {
|
||||
file(FileTemplateDescriptor("android/androidTest.kt.vm", relativePath = null), "androidTest.kt", SourcesetType.test)
|
||||
}
|
||||
|
||||
filesFor(ModuleSubType.iosArm64, ModuleSubType.iosX64, ModuleSubType.ios) {
|
||||
file(FileTemplateDescriptor("ios/iosTest.kt.vm", relativePath = null), "iosTest.kt", SourcesetType.test)
|
||||
}
|
||||
|
||||
}
|
||||
return inContextOfModuleConfigurator(mppModule) { MppModuleConfigurator.mppSources.reference.addValues(listOf(expectFiles)) }
|
||||
}
|
||||
+5
-1
@@ -13,6 +13,8 @@ import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ModuleType
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.SourcesetType
|
||||
import org.jetbrains.kotlin.tools.projectWizard.KotlinNewProjectWizardBundle
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.Reader
|
||||
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.moduleType
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.Module
|
||||
|
||||
class ConsoleJvmApplicationTemplate : Template() {
|
||||
@NonNls
|
||||
@@ -21,7 +23,9 @@ class ConsoleJvmApplicationTemplate : Template() {
|
||||
override val title: String = KotlinNewProjectWizardBundle.message("module.template.console.jvm.title")
|
||||
override val description: String = KotlinNewProjectWizardBundle.message("module.template.console.jvm.description")
|
||||
|
||||
override val moduleTypes: Set<ModuleType> = setOf(ModuleType.jvm)
|
||||
|
||||
override fun isSupportedByModuleType(module: Module): Boolean =
|
||||
module.configurator.moduleType == ModuleType.jvm
|
||||
|
||||
override fun Writer.getIrsToAddToBuildFile(
|
||||
module: ModuleIR
|
||||
|
||||
+2
-1
@@ -20,7 +20,8 @@ import org.jetbrains.kotlin.tools.projectWizard.transformers.interceptors.Templa
|
||||
import org.jetbrains.kotlin.tools.projectWizard.transformers.interceptors.interceptTemplate
|
||||
|
||||
abstract class JsClientTemplate : Template() {
|
||||
override val moduleTypes: Set<ModuleType> = setOf(ModuleType.js)
|
||||
override fun isSupportedByModuleType(module: Module): Boolean =
|
||||
module.configurator.moduleType == ModuleType.js
|
||||
|
||||
override fun isApplicableTo(
|
||||
reader: Reader,
|
||||
|
||||
+5
-5
@@ -18,23 +18,23 @@ import org.jetbrains.kotlin.tools.projectWizard.library.MavenArtifact
|
||||
import org.jetbrains.kotlin.tools.projectWizard.phases.GenerationPhase
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ModuleType
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.DisplayableSettingItem
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.DefaultRepository
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.Repositories
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.SourcesetType
|
||||
import org.jetbrains.kotlin.tools.projectWizard.transformers.interceptors.InterceptionPoint
|
||||
import org.jetbrains.kotlin.tools.projectWizard.KotlinNewProjectWizardBundle
|
||||
import org.jetbrains.kotlin.tools.projectWizard.Versions
|
||||
import org.jetbrains.kotlin.tools.projectWizard.WizardGradleRunConfiguration
|
||||
import org.jetbrains.kotlin.tools.projectWizard.WizardRunConfiguration
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.Reader
|
||||
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.moduleType
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.KotlinPlugin
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.ModuleKind
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.*
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.version.Version
|
||||
|
||||
class KtorServerTemplate : Template() {
|
||||
override val title: String = KotlinNewProjectWizardBundle.message("module.template.ktor.server.title")
|
||||
override val description: String = KotlinNewProjectWizardBundle.message("module.template.ktor.server.description")
|
||||
override val moduleTypes: Set<ModuleType> = setOf(ModuleType.jvm)
|
||||
|
||||
override fun isSupportedByModuleType(module: Module): Boolean =
|
||||
module.configurator.moduleType == ModuleType.jvm
|
||||
|
||||
@NonNls
|
||||
override val id: String = "ktorServer"
|
||||
|
||||
+4
-1
@@ -16,13 +16,16 @@ import org.jetbrains.kotlin.tools.projectWizard.KotlinNewProjectWizardBundle
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.*
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.safeAs
|
||||
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.NativeTargetConfigurator
|
||||
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.moduleType
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.Module
|
||||
|
||||
class NativeConsoleApplicationTemplate : Template() {
|
||||
override val title: String = KotlinNewProjectWizardBundle.message("module.template.native.console.title")
|
||||
override val description: String = KotlinNewProjectWizardBundle.message("module.template.native.console.description")
|
||||
|
||||
override val moduleTypes: Set<ModuleType> = setOf(ModuleType.native)
|
||||
override fun isSupportedByModuleType(module: Module): Boolean =
|
||||
module.configurator.moduleType == ModuleType.native
|
||||
|
||||
override val id: String = "nativeConsoleApp"
|
||||
|
||||
override fun isApplicableTo(
|
||||
|
||||
+4
-1
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.*
|
||||
import org.jetbrains.kotlin.tools.projectWizard.library.MavenArtifact
|
||||
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.JsNodeTargetConfigurator
|
||||
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.NodeJsSinglePlatformModuleConfigurator
|
||||
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.moduleType
|
||||
import org.jetbrains.kotlin.tools.projectWizard.phases.GenerationPhase
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ModuleType
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.DefaultRepository.Companion.JCENTER
|
||||
@@ -26,7 +27,9 @@ class SimpleNodeJsTemplate : Template() {
|
||||
|
||||
override val description: String = KotlinNewProjectWizardBundle.message("module.template.simple.nodejs.description")
|
||||
|
||||
override val moduleTypes: Set<ModuleType> = setOf(ModuleType.js)
|
||||
|
||||
override fun isSupportedByModuleType(module: Module): Boolean =
|
||||
module.configurator.moduleType == ModuleType.js
|
||||
|
||||
@NonNls
|
||||
override val id: String = "simpleNodeJs"
|
||||
|
||||
+32
-11
@@ -9,15 +9,13 @@ import org.jetbrains.kotlin.tools.projectWizard.core.*
|
||||
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.entity.settings.*
|
||||
import org.jetbrains.kotlin.tools.projectWizard.enumSettingImpl
|
||||
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.BuildSystemIR
|
||||
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.DependencyIR
|
||||
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.ModuleIR
|
||||
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.MultiplatformModuleIR
|
||||
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.*
|
||||
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle.multiplatform.TargetConfigurationIR
|
||||
import org.jetbrains.kotlin.tools.projectWizard.phases.GenerationPhase
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.RunConfigurationsPlugin
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.StructurePlugin
|
||||
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.DisplayableSettingItem
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.Module
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.version.Version
|
||||
@@ -73,7 +71,8 @@ abstract class Template : SettingsOwner, EntitiesOwnerDescriptor, DisplayableSet
|
||||
|
||||
abstract val title: String
|
||||
abstract val description: String
|
||||
abstract val moduleTypes: Set<ModuleType>
|
||||
|
||||
abstract fun isSupportedByModuleType(module: Module): Boolean
|
||||
|
||||
override val text: String get() = title
|
||||
|
||||
@@ -100,6 +99,10 @@ abstract class Template : SettingsOwner, EntitiesOwnerDescriptor, DisplayableSet
|
||||
module: ModuleIR
|
||||
): List<BuildSystemIR> = emptyList()
|
||||
|
||||
open fun Writer.runArbitratyTask(
|
||||
module: ModuleIR
|
||||
): TaskResult<Unit> = UNIT_SUCCESS
|
||||
|
||||
open fun updateTargetIr(
|
||||
module: ModuleIR,
|
||||
targetConfigurationIR: TargetConfigurationIR
|
||||
@@ -112,24 +115,39 @@ abstract class Template : SettingsOwner, EntitiesOwnerDescriptor, DisplayableSet
|
||||
|
||||
open fun Reader.createRunConfigurations(module: ModuleIR): List<WizardRunConfiguration> = emptyList()
|
||||
|
||||
|
||||
open fun Reader.updateModuleIR(module: ModuleIR): ModuleIR = module
|
||||
open fun Reader.updateBuildFileIRs(irs: List<BuildSystemIR>): List<BuildSystemIR> = irs
|
||||
|
||||
open fun createRootBuildFileIrs(): List<BuildSystemIR> = emptyList()
|
||||
|
||||
fun Writer.applyToSourceset(
|
||||
module: ModuleIR
|
||||
): TaskResult<TemplateApplicationResult> {
|
||||
): TaskResult<TemplateApplicationResult> = compute {
|
||||
|
||||
val librariesToAdd = getRequiredLibraries(module)
|
||||
val irsToAddToBuildFile = getIrsToAddToBuildFile(module)
|
||||
runArbitratyTask(module).ensure()
|
||||
|
||||
val targetsUpdater = when (module) {
|
||||
is MultiplatformModuleIR -> { target: TargetConfigurationIR ->
|
||||
if (target.targetName == module.name) updateTargetIr(module, target)
|
||||
else target
|
||||
}
|
||||
is FakeMultiplatformModuleIR -> {
|
||||
module.targets.map { expectedTarget ->
|
||||
{ configurationIR: TargetConfigurationIR ->
|
||||
if (configurationIR.targetName == expectedTarget.name) updateTargetIr(expectedTarget, configurationIR)
|
||||
else configurationIR
|
||||
}
|
||||
}.reduce(::compose)
|
||||
}
|
||||
else -> idFunction()
|
||||
}
|
||||
|
||||
RunConfigurationsPlugin.configurations.addValues(createRunConfigurations(module))
|
||||
|
||||
val result = TemplateApplicationResult(librariesToAdd, irsToAddToBuildFile, targetsUpdater)
|
||||
return result.asSuccess()
|
||||
TemplateApplicationResult(librariesToAdd, irsToAddToBuildFile, targetsUpdater) { updateModuleIR(it) }
|
||||
}
|
||||
|
||||
fun Reader.settingsAsMap(module: Module): Map<String, Any> = mutableMapOf<String, Any>().apply {
|
||||
@@ -290,13 +308,15 @@ fun Writer.applyTemplateToModule(
|
||||
data class TemplateApplicationResult(
|
||||
val librariesToAdd: List<DependencyIR>,
|
||||
val irsToAddToBuildFile: List<BuildSystemIR>,
|
||||
val updateTarget: (TargetConfigurationIR) -> TargetConfigurationIR
|
||||
val updateTarget: (TargetConfigurationIR) -> TargetConfigurationIR,
|
||||
val updateModuleIR: (ModuleIR) -> ModuleIR
|
||||
) {
|
||||
companion object {
|
||||
val EMPTY = TemplateApplicationResult(
|
||||
librariesToAdd = emptyList(),
|
||||
irsToAddToBuildFile = emptyList(),
|
||||
updateTarget = { it }
|
||||
updateTarget = { it },
|
||||
updateModuleIR = { it },
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -308,5 +328,6 @@ operator fun TemplateApplicationResult.plus(other: TemplateApplicationResult) =
|
||||
TemplateApplicationResult(
|
||||
librariesToAdd + other.librariesToAdd,
|
||||
irsToAddToBuildFile + other.irsToAddToBuildFile,
|
||||
updateTarget andThen other.updateTarget
|
||||
updateTarget andThen other.updateTarget,
|
||||
updateModuleIR andThen other.updateModuleIR,
|
||||
)
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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.templates.mpp
|
||||
|
||||
import org.jetbrains.annotations.NonNls
|
||||
import org.jetbrains.kotlin.tools.projectWizard.KotlinNewProjectWizardBundle
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.Reader
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.TaskResult
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.Writer
|
||||
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.BuildSystemIR
|
||||
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.ModuleIR
|
||||
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.RepositoryIR
|
||||
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle.irsList
|
||||
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.MppModuleConfigurator
|
||||
import org.jetbrains.kotlin.tools.projectWizard.mpp.applyMppStructure
|
||||
import org.jetbrains.kotlin.tools.projectWizard.mpp.mppSources
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ModuleSubType
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.pomIR
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.DefaultRepository
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.Module
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.SourcesetType
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.javaPackage
|
||||
import org.jetbrains.kotlin.tools.projectWizard.templates.FileTemplateDescriptor
|
||||
import org.jetbrains.kotlin.tools.projectWizard.templates.Template
|
||||
|
||||
class MobileMppTemplate : Template() {
|
||||
@NonNls
|
||||
override val id: String = "mobileMppModule"
|
||||
|
||||
override val title: String = KotlinNewProjectWizardBundle.message("module.template.mpp.mobile.title")
|
||||
override val description: String = KotlinNewProjectWizardBundle.message("module.template.mpp.mobile.description")
|
||||
|
||||
override fun isSupportedByModuleType(module: Module): Boolean =
|
||||
module.configurator == MppModuleConfigurator
|
||||
|
||||
|
||||
override fun Writer.getIrsToAddToBuildFile(module: ModuleIR): List<BuildSystemIR> = irsList {
|
||||
+RepositoryIR(DefaultRepository.JCENTER)
|
||||
}
|
||||
|
||||
override fun Writer.runArbitratyTask(module: ModuleIR): TaskResult<Unit> {
|
||||
val javaPackage = module.originalModule.javaPackage(pomIR())
|
||||
|
||||
val mpp = mppSources(javaPackage) {
|
||||
mppFile("Platform.kt") {
|
||||
`class`("Platform") {
|
||||
expectBody = "val platform: String"
|
||||
actualFor(
|
||||
ModuleSubType.android,
|
||||
actualBody = """actual val platform: String = "Android ${'$'}{android.os.Build.VERSION.SDK_INT}""""
|
||||
)
|
||||
|
||||
actualFor(
|
||||
ModuleSubType.iosArm64, ModuleSubType.iosX64, ModuleSubType.ios,
|
||||
actualBody =
|
||||
"""actual val platform: String = UIDevice.currentDevice.systemName() + " " + UIDevice.currentDevice.systemVersion"""
|
||||
) {
|
||||
import("platform.UIKit.UIDevice")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
filesFor(ModuleSubType.common) {
|
||||
file(FileTemplateDescriptor("mppCommon/Greeting.kt.vm", relativePath = null), "Greeting.kt", SourcesetType.main)
|
||||
}
|
||||
|
||||
filesFor(ModuleSubType.android) {
|
||||
file(FileTemplateDescriptor("android/androidTest.kt.vm", relativePath = null), "androidTest.kt", SourcesetType.test)
|
||||
}
|
||||
|
||||
filesFor(ModuleSubType.iosArm64, ModuleSubType.iosX64, ModuleSubType.ios) {
|
||||
file(FileTemplateDescriptor("ios/iosTest.kt.vm", relativePath = null), "iosTest.kt", SourcesetType.test)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return applyMppStructure(mpp, module.originalModule, module.path)
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.tools.projectWizard.core
|
||||
|
||||
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.mppSources
|
||||
import org.jetbrains.kotlin.tools.projectWizard.mpp.mppSources
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ModuleSubType
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
Reference in New Issue
Block a user