Wizard: move module templates to modules

This commit is contained in:
Ilya Kirillov
2020-01-16 20:27:49 +03:00
parent 5673804707
commit 0ebcf482ca
20 changed files with 221 additions and 199 deletions
@@ -1,5 +1,6 @@
package org.jetbrains.kotlin.tools.projectWizard.wizard.ui.secondStep package org.jetbrains.kotlin.tools.projectWizard.wizard.ui.secondStep
import com.intellij.ui.components.JBTabbedPane
import com.intellij.ui.components.panels.VerticalLayout import com.intellij.ui.components.panels.VerticalLayout
import org.jetbrains.kotlin.tools.projectWizard.core.entity.StringValidators import org.jetbrains.kotlin.tools.projectWizard.core.entity.StringValidators
import org.jetbrains.kotlin.tools.projectWizard.core.ValuesReadingContext import org.jetbrains.kotlin.tools.projectWizard.core.ValuesReadingContext
@@ -11,6 +12,7 @@ import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.*
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.components.DropDownComponent import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.components.DropDownComponent
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.components.TextFieldComponent import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.components.TextFieldComponent
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.setting.SettingsList import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.setting.SettingsList
import java.awt.BorderLayout
import javax.swing.BorderFactory import javax.swing.BorderFactory
import javax.swing.JComponent import javax.swing.JComponent
@@ -19,7 +21,13 @@ class ModuleSettingsComponent(valuesReadingContext: ValuesReadingContext) : Dyna
StringValidators.shouldNotBeBlank("Module name") and StringValidators.shouldNotBeBlank("Module name") and
StringValidators.shouldBeValidIdentifier("Module Name") StringValidators.shouldBeValidIdentifier("Module Name")
private val moduleConfiguratorSettingsList = SettingsList(emptyList(), valuesReadingContext) private val moduleConfiguratorSettingsList = SettingsList(emptyList(), valuesReadingContext).asSubComponent()
private val templateComponent = TemplatesComponent(valuesReadingContext).asSubComponent()
private val tabPanel = JBTabbedPane().apply {
add("Template", templateComponent.component)
add("Module Settings", moduleConfiguratorSettingsList.component)
}
private val nameField = TextFieldComponent( private val nameField = TextFieldComponent(
valuesReadingContext, valuesReadingContext,
@@ -32,15 +40,15 @@ class ModuleSettingsComponent(valuesReadingContext: ValuesReadingContext) : Dyna
).asSubComponent() ).asSubComponent()
override val component: JComponent = panel(VerticalLayout(5)) { override val component: JComponent = panel {
border = BorderFactory.createEmptyBorder( border = BorderFactory.createEmptyBorder(
UiConstants.GAP_BORDER_SIZE, UiConstants.GAP_BORDER_SIZE,
UiConstants.GAP_BORDER_SIZE, UiConstants.GAP_BORDER_SIZE,
UiConstants.GAP_BORDER_SIZE, UiConstants.GAP_BORDER_SIZE,
UiConstants.GAP_BORDER_SIZE UiConstants.GAP_BORDER_SIZE
) )
add(nameField.component) add(nameField.component, BorderLayout.NORTH)
add(moduleConfiguratorSettingsList.component) add(tabPanel, BorderLayout.CENTER)
} }
var module: Module? = null var module: Module? = null
@@ -57,6 +65,7 @@ class ModuleSettingsComponent(valuesReadingContext: ValuesReadingContext) : Dyna
|| module.configurator.moduleType != ModuleType.common || module.configurator.moduleType != ModuleType.common
moduleConfiguratorSettingsList.setSettings(module.configuratorSettings) moduleConfiguratorSettingsList.setSettings(module.configuratorSettings)
templateComponent.module = module
} }
} }
@@ -6,10 +6,9 @@ import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.Sourceset
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.DynamicComponent import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.DynamicComponent
class SourcesetSettingsComponent(valuesReadingContext: ValuesReadingContext) : DynamicComponent(valuesReadingContext) { class SourcesetSettingsComponent(valuesReadingContext: ValuesReadingContext) : DynamicComponent(valuesReadingContext) {
private val templatesComponent = TemplatesComponent(valuesReadingContext).asSubComponent()
private val dependenciesComponent = SourcesetDependenciesSettingsComponent(valuesReadingContext).asSubComponent() private val dependenciesComponent = SourcesetDependenciesSettingsComponent(valuesReadingContext).asSubComponent()
override val component = JBTabbedPane().apply { override val component = JBTabbedPane().apply {
add("Template", templatesComponent.component)
add("Dependencies", dependenciesComponent.component) add("Dependencies", dependenciesComponent.component)
} }
@@ -17,6 +16,5 @@ class SourcesetSettingsComponent(valuesReadingContext: ValuesReadingContext) : D
set(value) { set(value) {
field = value field = value
dependenciesComponent.sourceset = value dependenciesComponent.sourceset = value
templatesComponent.sourceset = value
} }
} }
@@ -10,6 +10,7 @@ import com.intellij.util.ui.UIUtil
import org.jetbrains.kotlin.idea.KotlinIcons import org.jetbrains.kotlin.idea.KotlinIcons
import org.jetbrains.kotlin.tools.projectWizard.core.ValuesReadingContext import org.jetbrains.kotlin.tools.projectWizard.core.ValuesReadingContext
import org.jetbrains.kotlin.tools.projectWizard.plugins.templates.TemplatesPlugin import org.jetbrains.kotlin.tools.projectWizard.plugins.templates.TemplatesPlugin
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.Module
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.Sourceset import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.Sourceset
import org.jetbrains.kotlin.tools.projectWizard.templates.Template import org.jetbrains.kotlin.tools.projectWizard.templates.Template
import org.jetbrains.kotlin.tools.projectWizard.templates.settings import org.jetbrains.kotlin.tools.projectWizard.templates.settings
@@ -23,7 +24,7 @@ import javax.swing.JPanel
class TemplatesComponent(valuesReadingContext: ValuesReadingContext) : DynamicComponent(valuesReadingContext) { class TemplatesComponent(valuesReadingContext: ValuesReadingContext) : DynamicComponent(valuesReadingContext) {
private val chooseTemplateComponent: ChooseTemplateComponent = private val chooseTemplateComponent: ChooseTemplateComponent =
ChooseTemplateComponent(valuesReadingContext) { template -> ChooseTemplateComponent(valuesReadingContext) { template ->
sourceset?.template = template module?.template = template
switchState(template) switchState(template)
} }
@@ -46,8 +47,8 @@ class TemplatesComponent(valuesReadingContext: ValuesReadingContext) : DynamicCo
when (selectedTemplate) { when (selectedTemplate) {
null -> panel.add(chooseTemplateComponent.component, BorderLayout.CENTER) null -> panel.add(chooseTemplateComponent.component, BorderLayout.CENTER)
else -> { else -> {
if (sourceset != null) { if (module != null) {
templateSettingsComponent.setTemplate(sourceset!!, selectedTemplate) templateSettingsComponent.setTemplate(module!!, selectedTemplate)
} }
panel.add(templateSettingsComponent.component, BorderLayout.CENTER) panel.add(templateSettingsComponent.component, BorderLayout.CENTER)
} }
@@ -61,7 +62,7 @@ class TemplatesComponent(valuesReadingContext: ValuesReadingContext) : DynamicCo
override val component: JComponent = panel override val component: JComponent = panel
var sourceset: Sourceset? = null var module: Module? = null
set(value) { set(value) {
field = value field = value
switchState(value?.template) switchState(value?.template)
@@ -95,7 +96,7 @@ class ChooseTemplateComponent(
TemplatesPlugin::templates.propertyValue TemplatesPlugin::templates.propertyValue
} }
var selectedModule: Sourceset? = null var selectedModule: Module? = null
set(value) { set(value) {
field = value field = value
onStateUpdated() onStateUpdated()
@@ -107,8 +108,7 @@ class ChooseTemplateComponent(
private val availableTemplates private val availableTemplates
get() = allTemplates.values.filter { template -> get() = allTemplates.values.filter { template ->
selectedModule!!.containingModuleType in template.moduleTypes selectedModule!!.configurator.moduleType in template.moduleTypes
&& selectedModule!!.sourcesetType in template.sourcesetTypes
&& template.isApplicableTo(selectedModule!!) && template.isApplicableTo(selectedModule!!)
} }
@@ -204,7 +204,7 @@ class TemplateDescriptionComponent(
} }
private val title = panel { private val title = panel {
nonDefaultBackgroundColor?.let { background = it } nonDefaultBackgroundColor?.let { background = it }
add(titleLabel, BorderLayout.CENTER) add(titleLabel, BorderLayout.CENTER)
removeButton?.let { add(it, BorderLayout.EAST) } removeButton?.let { add(it, BorderLayout.EAST) }
} }
@@ -213,7 +213,7 @@ class TemplateDescriptionComponent(
override val component: JComponent by lazy(LazyThreadSafetyMode.NONE) { override val component: JComponent by lazy(LazyThreadSafetyMode.NONE) {
panel { panel {
nonDefaultBackgroundColor?.let { background = it } nonDefaultBackgroundColor?.let { background = it }
add(title, BorderLayout.NORTH) add(title, BorderLayout.NORTH)
add(descriptionLabel, BorderLayout.CENTER) add(descriptionLabel, BorderLayout.CENTER)
} }
@@ -239,7 +239,7 @@ private class TemplateSettingsComponent(
) : DynamicComponent(valuesReadingContext) { ) : DynamicComponent(valuesReadingContext) {
private val templateDescriptionComponent = TemplateDescriptionComponent( private val templateDescriptionComponent = TemplateDescriptionComponent(
needRemoveButton = true, needRemoveButton = true,
nonDefaultBackgroundColor = UIUtil.getEditorPaneBackground(), nonDefaultBackgroundColor = UIUtil.getEditorPaneBackground(),
onRemoveButtonClicked = removeTemplate onRemoveButtonClicked = removeTemplate
).apply { ).apply {
component.bordered(needTopEmptyBorder = false, needBottomEmptyBorder = false) component.bordered(needTopEmptyBorder = false, needBottomEmptyBorder = false)
@@ -249,8 +249,8 @@ private class TemplateSettingsComponent(
component.bordered() component.bordered()
} }
fun setTemplate(sourceset: Sourceset, selectedTemplate: Template) { fun setTemplate(module: Module, selectedTemplate: Template) {
settings.setSettings(selectedTemplate.settings(sourceset)) settings.setSettings(selectedTemplate.settings(module))
templateDescriptionComponent.updateSelectedTemplate(selectedTemplate) templateDescriptionComponent.updateSelectedTemplate(selectedTemplate)
} }
@@ -28,7 +28,6 @@ class NewModuleCreator {
Sourceset( Sourceset(
sourcesetType, sourcesetType,
configurator.moduleType, configurator.moduleType,
template = null,
dependencies = emptyList() dependencies = emptyList()
) )
} }
@@ -57,7 +56,6 @@ class NewModuleCreator {
Sourceset( Sourceset(
sourcesetType, sourcesetType,
ModuleType.jvm, ModuleType.jvm,
template = null,
dependencies = emptyList() dependencies = emptyList()
) )
} }
@@ -66,8 +64,9 @@ class NewModuleCreator {
name, name,
configurator.moduleKind, configurator.moduleKind,
configurator, configurator,
sourcesets, template = null,
emptyList() sourcesets = sourcesets,
subModules = emptyList()
) )
createModule(createdModule) createModule(createdModule)
} }
@@ -2,7 +2,6 @@ package org.jetbrains.kotlin.tools.projectWizard.core.entity
import org.jetbrains.kotlin.tools.projectWizard.Identificator import org.jetbrains.kotlin.tools.projectWizard.Identificator
import org.jetbrains.kotlin.tools.projectWizard.core.* import org.jetbrains.kotlin.tools.projectWizard.core.*
import org.jetbrains.kotlin.tools.projectWizard.id
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.ModuleConfigurator import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.ModuleConfigurator
import org.jetbrains.kotlin.tools.projectWizard.phases.GenerationPhase import org.jetbrains.kotlin.tools.projectWizard.phases.GenerationPhase
import org.jetbrains.kotlin.tools.projectWizard.settings.DisplayableSettingItem import org.jetbrains.kotlin.tools.projectWizard.settings.DisplayableSettingItem
@@ -71,16 +70,16 @@ sealed class TemplateSettingReference<V : Any, T : SettingType<V>> : SettingRefe
get() = setting.type::class get() = setting.type::class
override fun Context.getSetting(): Setting<V, T> = setting override fun Context.getSetting(): Setting<V, T> = setting
abstract val sourceset: Sourceset? abstract val module: Module?
} }
data class SourcesetBasedTemplateSettingReference<V : Any, T : SettingType<V>>( data class ModuleBasedTemplateSettingReference<V : Any, T : SettingType<V>>(
override val descriptor: Template, override val descriptor: Template,
override val sourceset: Sourceset, override val module: Module,
override val setting: TemplateSetting<V, T> override val setting: TemplateSetting<V, T>
) : TemplateSettingReference<V, T>() { ) : TemplateSettingReference<V, T>() {
override val sourcesetId: Identificator override val sourcesetId: Identificator
get() = sourceset.identificator get() = module.identificator
} }
data class IdBasedTemplateSettingReference<V : Any, T : SettingType<V>>( data class IdBasedTemplateSettingReference<V : Any, T : SettingType<V>>(
@@ -88,7 +87,7 @@ data class IdBasedTemplateSettingReference<V : Any, T : SettingType<V>>(
override val sourcesetId: Identificator, override val sourcesetId: Identificator,
override val setting: TemplateSetting<V, T> override val setting: TemplateSetting<V, T>
) : TemplateSettingReference<V, T>() { ) : TemplateSettingReference<V, T>() {
override val sourceset: Sourceset? = null override val module: Module? = null
} }
inline val <V : Any, reified T : SettingType<V>> PluginSettingPropertyReference<V, T>.reference: PluginSettingReference<V, T> inline val <V : Any, reified T : SettingType<V>> PluginSettingPropertyReference<V, T>.reference: PluginSettingReference<V, T>
@@ -5,6 +5,7 @@ import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ModuleType
import org.jetbrains.kotlin.tools.projectWizard.plugins.printer.BuildFilePrinter 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.GradlePrinter
import org.jetbrains.kotlin.tools.projectWizard.plugins.printer.MavenPrinter import org.jetbrains.kotlin.tools.projectWizard.plugins.printer.MavenPrinter
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.Module
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.Sourceset import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.Sourceset
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.SourcesetType import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.SourcesetType
import org.jetbrains.kotlin.tools.projectWizard.templates.Template import org.jetbrains.kotlin.tools.projectWizard.templates.Template
@@ -13,14 +14,15 @@ import java.nio.file.Path
sealed class ModuleIR : IrsOwner, BuildSystemIR { sealed class ModuleIR : IrsOwner, BuildSystemIR {
abstract val name: String abstract val name: String
abstract val path: Path abstract val path: Path
abstract val template: Template?
abstract val type: ModuleType abstract val type: ModuleType
abstract val originalModule: Module
} }
interface SourcesetIR : BuildSystemIR { interface SourcesetIR : BuildSystemIR {
val sourcesetType: SourcesetType val sourcesetType: SourcesetType
val path: Path val path: Path
val template: Template?
val original: Sourceset val original: Sourceset
} }
@@ -28,7 +30,9 @@ data class SingleplatformModuleIR(
override val name: String, override val name: String,
override val path: Path, override val path: Path,
override val irs: List<BuildSystemIR>, override val irs: List<BuildSystemIR>,
override val template: Template?,
override val type: ModuleType, override val type: ModuleType,
override val originalModule: Module,
val sourcesets: List<SingleplatformSourcesetIR> val sourcesets: List<SingleplatformSourcesetIR>
) : ModuleIR() { ) : ModuleIR() {
override fun withReplacedIrs(irs: List<BuildSystemIR>): SingleplatformModuleIR = copy(irs = irs) override fun withReplacedIrs(irs: List<BuildSystemIR>): SingleplatformModuleIR = copy(irs = irs)
@@ -51,7 +55,6 @@ data class SingleplatformSourcesetIR(
override val sourcesetType: SourcesetType, override val sourcesetType: SourcesetType,
override val path: Path, override val path: Path,
override val irs: List<BuildSystemIR>, override val irs: List<BuildSystemIR>,
override val template: Template?,
override val original: Sourceset override val original: Sourceset
) : SourcesetIR, IrsOwner { ) : SourcesetIR, IrsOwner {
override fun withReplacedIrs(irs: List<BuildSystemIR>): SingleplatformSourcesetIR = copy(irs = irs) override fun withReplacedIrs(irs: List<BuildSystemIR>): SingleplatformSourcesetIR = copy(irs = irs)
@@ -65,6 +68,7 @@ data class SourcesetModuleIR(
override val type: ModuleType, override val type: ModuleType,
override val sourcesetType: SourcesetType, override val sourcesetType: SourcesetType,
override val template: Template?, override val template: Template?,
override val originalModule: Module,
override val original: Sourceset override val original: Sourceset
) : SourcesetIR, GradleIR, ModuleIR() { ) : SourcesetIR, GradleIR, ModuleIR() {
override fun withReplacedIrs(irs: List<BuildSystemIR>): SourcesetModuleIR = copy(irs = irs) override fun withReplacedIrs(irs: List<BuildSystemIR>): SourcesetModuleIR = copy(irs = irs)
@@ -104,7 +104,7 @@ abstract class GradlePlugin(context: Context) : BuildSystemPlugin(context) {
} }
val createSettingsFileTask by pipelineTask(GenerationPhase.PROJECT_GENERATION) { val createSettingsFileTask by pipelineTask(GenerationPhase.PROJECT_GENERATION) {
runBefore(TemplatesPlugin::addTemplatesToSourcesets) runBefore(TemplatesPlugin::addTemplatesToModules)
activityChecker = isGradle activityChecker = isGradle
withAction { withAction {
val templateDescriptor = when (buildSystemType) { val templateDescriptor = when (buildSystemType) {
@@ -119,13 +119,14 @@ class ModulesToIRsConverter(
module.name, module.name,
modulePath, modulePath,
dependenciesIRs, dependenciesIRs,
module.template,
module.configurator.moduleType, module.configurator.moduleType,
module,
module.sourcesets.map { sourceset -> module.sourcesets.map { sourceset ->
SingleplatformSourcesetIR( SingleplatformSourcesetIR(
sourceset.sourcesetType, sourceset.sourcesetType,
modulePath / Defaults.SRC_DIR / sourceset.sourcesetType.name, modulePath / Defaults.SRC_DIR / sourceset.sourcesetType.name,
sourceset.dependencies.map { it.toIR(sourceset.sourcesetType.toDependencyType()) }, sourceset.dependencies.map { it.toIR(sourceset.sourcesetType.toDependencyType()) },
sourceset.template,
sourceset sourceset
) )
} }
@@ -203,7 +204,8 @@ class ModulesToIRsConverter(
sourcesetIrs, sourcesetIrs,
sourceset.containingModuleType, sourceset.containingModuleType,
sourceset.sourcesetType, sourceset.sourcesetType,
sourceset.template, target.template,
target,
sourceset sourceset
) )
} }
@@ -1,6 +1,9 @@
package org.jetbrains.kotlin.tools.projectWizard.plugins.templates package org.jetbrains.kotlin.tools.projectWizard.plugins.templates
import org.jetbrains.kotlin.tools.projectWizard.core.* import org.jetbrains.kotlin.tools.projectWizard.core.*
import org.jetbrains.kotlin.tools.projectWizard.core.Defaults.KOTLIN_DIR
import org.jetbrains.kotlin.tools.projectWizard.core.Defaults.RESOURCES_DIR
import org.jetbrains.kotlin.tools.projectWizard.core.Defaults.SRC_DIR
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.* import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.*
import org.jetbrains.kotlin.tools.projectWizard.phases.GenerationPhase import org.jetbrains.kotlin.tools.projectWizard.phases.GenerationPhase
import org.jetbrains.kotlin.tools.projectWizard.plugins.buildSystem.BuildSystemPlugin import org.jetbrains.kotlin.tools.projectWizard.plugins.buildSystem.BuildSystemPlugin
@@ -46,7 +49,7 @@ class TemplatesPlugin(context: Context) : Plugin(context) {
} }
} }
val addTemplatesToSourcesets by pipelineTask(GenerationPhase.PROJECT_GENERATION) { val addTemplatesToModules by pipelineTask(GenerationPhase.PROJECT_GENERATION) {
runBefore(BuildSystemPlugin::createModules) runBefore(BuildSystemPlugin::createModules)
runAfter(KotlinPlugin::createModules) runAfter(KotlinPlugin::createModules)
@@ -54,30 +57,10 @@ class TemplatesPlugin(context: Context) : Plugin(context) {
val templateEngine = VelocityTemplateEngine() val templateEngine = VelocityTemplateEngine()
updateBuildFiles { buildFile -> updateBuildFiles { buildFile ->
buildFile.modules.modules.mapSequence { module -> buildFile.modules.modules.mapSequence { module ->
when (module) { applyTemplateToModule(
is SingleplatformModuleIR -> { module.template,
module.sourcesets.mapSequence { sourceset -> module
applyTemplateToSourceset( ).map { result -> module.withIrs(result.librariesToAdd) to result }
sourceset.template,
sourceset,
templateEngine
).map { result ->
result.copy(
librariesToAdd = result.librariesToAdd.map {
it.withDependencyType(sourceset.sourcesetType.toDependencyType())
}
)
}
}.map(List<TemplateApplicationResult>::fold)
}
is SourcesetModuleIR -> {
applyTemplateToSourceset(
module.template,
module,
templateEngine
)
}
}.map { result -> module.withIrs(result.librariesToAdd) to result }
}.map { }.map {
val (moduleIrs, results) = it.unzip() val (moduleIrs, results) = it.unzip()
val foldedResults = results.fold() val foldedResults = results.fold()
@@ -95,25 +78,25 @@ class TemplatesPlugin(context: Context) : Plugin(context) {
} }
} }
val postApplyTemplatesToSourcesets by pipelineTask(GenerationPhase.PROJECT_GENERATION) { val postApplyTemplatesToModules by pipelineTask(GenerationPhase.PROJECT_GENERATION) {
runBefore(BuildSystemPlugin::createModules) runBefore(BuildSystemPlugin::createModules)
runAfter(KotlinPlugin::createModules) runAfter(KotlinPlugin::createModules)
runAfter(TemplatesPlugin::addTemplatesToSourcesets) runAfter(TemplatesPlugin::addTemplatesToModules)
withAction { withAction {
updateBuildFiles { buildFile -> updateBuildFiles { buildFile ->
val sourcesets = buildFile.sourcesets val modules = buildFile.modules.modules
val applicationState = sourcesets.mapNotNull { sourceset -> val applicationState = modules.mapNotNull { module ->
sourceset.template?.createInterceptors(sourceset) module.template?.createInterceptors(module)
}.flatten() }.flatten()
.applyAll(TemplateInterceptionApplicationState(buildFile, emptyMap())) .applyAll(TemplateInterceptionApplicationState(buildFile, emptyMap()))
val templateEngine = VelocityTemplateEngine() val templateEngine = VelocityTemplateEngine()
val templatesApplicationResult = sourcesets.map { sourceset -> val templatesApplicationResult = modules.map { module ->
val settings = applicationState.sourcesetToSettings[sourceset.original.identificator].orEmpty() val settings = applicationState.moduleToSettings[module.originalModule.identificator].orEmpty()
applyFileTemplatesFromSourceset(sourceset, templateEngine, settings) applyFileTemplatesFromSourceset(module, templateEngine, settings)
}.sequenceIgnore() }.sequenceIgnore()
templatesApplicationResult andThen applicationState.buildFileIR.asSuccess() templatesApplicationResult andThen applicationState.buildFileIR.asSuccess()
@@ -122,16 +105,39 @@ class TemplatesPlugin(context: Context) : Plugin(context) {
} }
private fun TaskRunningContext.applyFileTemplatesFromSourceset( private fun TaskRunningContext.applyFileTemplatesFromSourceset(
sourceset: SourcesetIR, module: ModuleIR,
templateEngine: TemplateEngine, templateEngine: TemplateEngine,
interceptionPointSettings: Map<InterceptionPoint<Any>, Any> interceptionPointSettings: Map<InterceptionPoint<Any>, Any>
): TaskResult<Unit> { ): TaskResult<Unit> {
val template = sourceset.template ?: return UNIT_SUCCESS val template = module.template ?: return UNIT_SUCCESS
val settings = with(template) { settingsAsMap(sourceset.original) } val settings = with(template) { settingsAsMap(module.originalModule) }
val allSettings = settings + interceptionPointSettings.mapKeys { it.key.name } val allSettings = settings + interceptionPointSettings.mapKeys { it.key.name }
return with(template) { getFileTemplates(sourceset) }.map { fileTemplateDescriptor -> return with(template) { getFileTemplates(module) }.mapNotNull { (fileTemplateDescriptor, filePath) ->
val fileTemplate = FileTemplate(fileTemplateDescriptor, sourceset.path, allSettings) val path = generatePathForFileTemplate(module, filePath) ?: return@mapNotNull null
val fileTemplate = FileTemplate(
fileTemplateDescriptor,
module.path / path,
allSettings
)
with(templateEngine) { writeTemplate(fileTemplate) } with(templateEngine) { writeTemplate(fileTemplate) }
}.sequenceIgnore() }.sequenceIgnore()
} }
private fun generatePathForFileTemplate(module: ModuleIR, filePath: FilePath) = when (module) {
is SingleplatformModuleIR -> {
when (filePath) {
is SrcFilePath -> SRC_DIR / filePath.sourcesetType.toString() / KOTLIN_DIR
is ResourcesFilePath -> RESOURCES_DIR / filePath.sourcesetType.toString()
}
}
is SourcesetModuleIR -> {
if (filePath.sourcesetType == module.sourcesetType) {
when (filePath) {
is SrcFilePath -> KOTLIN_DIR
is ResourcesFilePath -> RESOURCES_DIR
}
} else null
}
}
} }
@@ -5,12 +5,10 @@ import org.jetbrains.kotlin.tools.projectWizard.core.buildList
import org.jetbrains.kotlin.tools.projectWizard.core.entity.* import org.jetbrains.kotlin.tools.projectWizard.core.entity.*
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.AndroidSinglePlatformModuleConfigurator import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.AndroidSinglePlatformModuleConfigurator
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.MppModuleConfigurator import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.MppModuleConfigurator
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.NativeForCurrentSystemTarget
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.defaultTarget import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.defaultTarget
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.KotlinPlugin import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.KotlinPlugin
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.ProjectKind import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ProjectKind
import org.jetbrains.kotlin.tools.projectWizard.projectTemplates.MultiplatformLibrary.withTemplate
import org.jetbrains.kotlin.tools.projectWizard.settings.DisplayableSettingItem import org.jetbrains.kotlin.tools.projectWizard.settings.DisplayableSettingItem
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.* import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.*
import org.jetbrains.kotlin.tools.projectWizard.templates.* import org.jetbrains.kotlin.tools.projectWizard.templates.*
@@ -36,7 +34,7 @@ sealed class ProjectTemplate : DisplayableSettingItem {
} }
fun <T : Template> Sourceset.withTemplate( fun <T : Template> Module.withTemplate(
template: T, template: T,
createSettings: TemplateSettingsBuilder<T>.() -> Unit = {} createSettings: TemplateSettingsBuilder<T>.() -> Unit = {}
) = apply { ) = apply {
@@ -62,9 +60,9 @@ sealed class ProjectTemplate : DisplayableSettingItem {
} }
class TemplateSettingsBuilder<Q : Template>( class TemplateSettingsBuilder<Q : Template>(
val sourceset: Sourceset, val module: Module,
val template: Q val template: Q
) : TemplateEnvironment by SourcesetBasedTemplateEnvironment(template, sourceset) { ) : TemplateEnvironment by ModuleBasedTemplateEnvironment(template, module) {
private val settings = mutableListOf<SettingWithValue<*, *>>() private val settings = mutableListOf<SettingWithValue<*, *>>()
val setsSettings: List<SettingWithValue<*, *>> val setsSettings: List<SettingWithValue<*, *>>
get() = settings get() = settings
@@ -89,7 +87,6 @@ private fun ModuleType.createDefaultSourcesets() =
Sourceset( Sourceset(
sourcesetType, sourcesetType,
this, this,
template = null,
dependencies = emptyList() dependencies = emptyList()
) )
} }
@@ -138,7 +135,7 @@ object JvmConsoleApplication : ProjectTemplate() {
"consoleApp", "consoleApp",
ModuleType.jvm.createDefaultSourcesets() ModuleType.jvm.createDefaultSourcesets()
).apply { ).apply {
mainSourceset?.withTemplate(ConsoleJvmApplicationTemplate()) withTemplate(ConsoleJvmApplicationTemplate())
} }
) )
) )
@@ -161,22 +158,22 @@ object MultiplatformLibrary : ProjectTemplate() {
"library", "library",
listOf( listOf(
ModuleType.common.createDefaultTarget().apply { ModuleType.common.createDefaultTarget().apply {
testSourceset?.withTemplate(KotlinTestTemplate()) { // testSourceset?.withTemplate(KotlinTestTemplate()) {
template.framework withValue KotlinTestFramework.COMMON // template.framework withValue KotlinTestFramework.COMMON
template.generateDummyTest withValue false // template.generateDummyTest withValue false
} // }
}, },
ModuleType.jvm.createDefaultTarget().apply { ModuleType.jvm.createDefaultTarget().apply {
testSourceset?.withTemplate(KotlinTestTemplate()) { // testSourceset?.withTemplate(KotlinTestTemplate()) {
template.framework withValue KotlinTestFramework.JUNIT4 // template.framework withValue KotlinTestFramework.JUNIT4
template.generateDummyTest withValue false // template.generateDummyTest withValue false
} // }
}, },
ModuleType.js.createDefaultTarget().apply { ModuleType.js.createDefaultTarget().apply {
testSourceset?.withTemplate(KotlinTestTemplate()) { // testSourceset?.withTemplate(KotlinTestTemplate()) {
template.framework withValue KotlinTestFramework.JS // template.framework withValue KotlinTestFramework.JS
template.generateDummyTest withValue false // template.generateDummyTest withValue false
} // }
}, },
ModuleType.native.createDefaultTarget() ModuleType.native.createDefaultTarget()
) )
@@ -197,12 +194,12 @@ object JvmServerJsClient : ProjectTemplate() {
"application", "application",
listOf( listOf(
ModuleType.jvm.createDefaultTarget().apply { ModuleType.jvm.createDefaultTarget().apply {
mainSourceset?.withTemplate(KtorServerTemplate()) { withTemplate(KtorServerTemplate()) {
template.serverEngine withValue KtorServerEngine.Netty template.serverEngine withValue KtorServerEngine.Netty
} }
}, },
ModuleType.js.createDefaultTarget().apply { ModuleType.js.createDefaultTarget().apply {
mainSourceset?.withTemplate(SimpleJsClientTemplate()) withTemplate(SimpleJsClientTemplate())
} }
) )
) )
@@ -226,8 +223,9 @@ object AndroidApplication : ProjectTemplate() {
"app", "app",
ModuleKind.singleplatform, ModuleKind.singleplatform,
AndroidSinglePlatformModuleConfigurator, AndroidSinglePlatformModuleConfigurator,
SourcesetType.ALL.map { type -> template = null,
Sourceset(type, ModuleType.jvm, template = null, dependencies = emptyList()) sourcesets = SourcesetType.ALL.map { type ->
Sourceset(type, ModuleType.jvm, dependencies = emptyList())
}, },
subModules = emptyList() subModules = emptyList()
) )
@@ -248,10 +246,11 @@ object NativeConsoleApplication : ProjectTemplate() {
"app", "app",
ModuleKind.multiplatform, ModuleKind.multiplatform,
MppModuleConfigurator, MppModuleConfigurator,
emptyList(), template = null,
sourcesets = emptyList(),
subModules = listOf( subModules = listOf(
ModuleType.native.createDefaultTarget("native").apply { ModuleType.native.createDefaultTarget("native").apply {
mainSourceset?.withTemplate(NativeConsoleApplicationTemplate()) withTemplate(NativeConsoleApplicationTemplate())
} }
) )
) )
@@ -7,6 +7,7 @@ import org.jetbrains.kotlin.tools.projectWizard.core.*
import org.jetbrains.kotlin.tools.projectWizard.core.entity.* import org.jetbrains.kotlin.tools.projectWizard.core.entity.*
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.* import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.*
import org.jetbrains.kotlin.tools.projectWizard.settings.DisplayableSettingItem import org.jetbrains.kotlin.tools.projectWizard.settings.DisplayableSettingItem
import org.jetbrains.kotlin.tools.projectWizard.templates.Template
@Suppress("EnumEntryName") @Suppress("EnumEntryName")
enum class ModuleKind { enum class ModuleKind {
@@ -20,6 +21,7 @@ class Module(
var name: String, var name: String,
val kind: ModuleKind, val kind: ModuleKind,
var configurator: ModuleConfigurator, var configurator: ModuleConfigurator,
var template: Template?,
val sourcesets: List<Sourceset>, val sourcesets: List<Sourceset>,
subModules: List<Module>, subModules: List<Module>,
var parent: Module? = null, var parent: Module? = null,
@@ -38,8 +40,15 @@ class Module(
setting.validator.validate(this@settingValidator, value) setting.validator.validate(this@settingValidator, value)
}.fold() }.fold()
} }
} and inValidatorContext { module -> } and settingValidator { module ->
validateList(module.sourcesets) val template = module.template ?: return@settingValidator ValidationResult.OK
org.jetbrains.kotlin.tools.projectWizard.templates.withSettingsOf(module) {
template.settings.map { setting ->
val value = setting.reference.notRequiredSettingValue
?: return@map ValidationResult.ValidationError("${setting.title.capitalize()} should not be blank")
setting.validator.validate(this@settingValidator, value)
}.fold()
}
} and inValidatorContext { module -> } and inValidatorContext { module ->
validateList(module.subModules) validateList(module.subModules)
} }
@@ -72,6 +81,9 @@ class Module(
val identificator = GeneratedIdentificator(name) val identificator = GeneratedIdentificator(name)
val (kind) = map.parseValue<ModuleKind>(this, path, "kind", enumParser()) val (kind) = map.parseValue<ModuleKind>(this, path, "kind", enumParser())
val (configurator) = map.parseValue(this, path, "type", ModuleConfigurator.getParser(identificator)) val (configurator) = map.parseValue(this, path, "type", ModuleConfigurator.getParser(identificator))
val template = map["template"]?.let {
Template.parser(identificator).parse(this, it, "$path.template")
}.nullableValue()
val (sourcesets) = map.parseValue( val (sourcesets) = map.parseValue(
this, this,
path, path,
@@ -79,7 +91,7 @@ class Module(
listParser(Sourceset.parser(configurator.moduleType)) listParser(Sourceset.parser(configurator.moduleType))
) { emptyList() } ) { emptyList() }
val (submodules) = map.parseValue(this, path, "subModules", listParser(Module.parser)) { emptyList() } val (submodules) = map.parseValue(this, path, "subModules", listParser(Module.parser)) { emptyList() }
Module(name, kind, configurator, sourcesets, submodules, identificator = identificator) Module(name, kind, configurator, template, sourcesets, submodules, identificator = identificator)
} }
} }
@@ -111,6 +123,7 @@ fun MultiplatformTargetModule(name: String, configurator: ModuleConfigurator, so
name, name,
ModuleKind.target, ModuleKind.target,
configurator, configurator,
null,
sourcesets, sourcesets,
emptyList() emptyList()
) )
@@ -121,6 +134,7 @@ fun MultiplatformModule(name: String, targets: List<Module> = emptyList()) =
name, name,
ModuleKind.multiplatform, ModuleKind.multiplatform,
MppModuleConfigurator, MppModuleConfigurator,
null,
emptyList(), emptyList(),
targets targets
) )
@@ -131,6 +145,7 @@ fun SingleplatformModule(name: String, sourcesets: List<Sourceset>) =
name, name,
ModuleKind.singleplatform, ModuleKind.singleplatform,
JvmSinglePlatformModuleConfigurator, JvmSinglePlatformModuleConfigurator,
null,
sourcesets, sourcesets,
emptyList() emptyList()
) )
@@ -36,21 +36,10 @@ data class PathBasedSourcesetDependency(val path: ModulePath) : SourcesetDepende
class Sourceset( class Sourceset(
val sourcesetType: SourcesetType, val sourcesetType: SourcesetType,
val containingModuleType: ModuleType, val containingModuleType: ModuleType,
var template: Template?,
var dependencies: List<SourcesetDependency>, var dependencies: List<SourcesetDependency>,
var parent: Module? = null, var parent: Module? = null,
override val identificator: Identificator = GeneratedIdentificator(sourcesetType.name) override val identificator: Identificator = GeneratedIdentificator(sourcesetType.name)
) : DisplayableSettingItem, Validatable<Sourceset>, IdentificatorOwner { ) : DisplayableSettingItem, IdentificatorOwner {
override val validator: SettingValidator<Sourceset> = settingValidator { sourceset ->
val template = sourceset.template ?: return@settingValidator ValidationResult.OK
withSettingsOf(sourceset) {
template.settings.map { setting ->
val value = setting.reference.notRequiredSettingValue
?: return@map ValidationResult.ValidationError("${setting.title.capitalize()} should not be blank")
setting.validator.validate(this@settingValidator, value)
}.fold()
}
}
override val text: String get() = sourcesetType.name override val text: String get() = sourcesetType.name
override val greyText: String? get() = null override val greyText: String? get() = null
@@ -64,11 +53,8 @@ class Sourceset(
"dependencies", "dependencies",
listParser(PathBasedSourcesetDependency.parser) listParser(PathBasedSourcesetDependency.parser)
) { emptyList() } ) { emptyList() }
val template = map["template"]?.let {
Template.parser(identificator).parse(this, it, "$path.template")
}.nullableValue()
Sourceset(sourcesetType, moduleType, template, dependencies, identificator = identificator) Sourceset(sourcesetType, moduleType, dependencies, identificator = identificator)
} }
} }
} }
@@ -2,6 +2,7 @@ package org.jetbrains.kotlin.tools.projectWizard.templates
import org.jetbrains.kotlin.tools.projectWizard.core.buildList import org.jetbrains.kotlin.tools.projectWizard.core.buildList
import org.jetbrains.kotlin.tools.projectWizard.core.TaskRunningContext import org.jetbrains.kotlin.tools.projectWizard.core.TaskRunningContext
import org.jetbrains.kotlin.tools.projectWizard.core.asPath
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.* 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.ir.buildsystem.gradle.multiplatform.TargetConfigurationIR
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle.multiplatform.addWithJavaIntoJvmTarget import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle.multiplatform.addWithJavaIntoJvmTarget
@@ -15,19 +16,18 @@ class ConsoleJvmApplicationTemplate : Template() {
Console JVM module with main method and run task generated Console JVM module with main method and run task generated
""".trimIndent() """.trimIndent()
override val moduleTypes: Set<ModuleType> = setOf(ModuleType.jvm) override val moduleTypes: Set<ModuleType> = setOf(ModuleType.jvm)
override val sourcesetTypes: Set<SourcesetType> = setOf(SourcesetType.main)
override fun TaskRunningContext.getIrsToAddToBuildFile( override fun TaskRunningContext.getIrsToAddToBuildFile(
sourceset: SourcesetIR module: ModuleIR
) = buildList<BuildSystemIR> { ) = buildList<BuildSystemIR> {
+runTaskIrs("MainKt") +runTaskIrs("MainKt")
} }
override fun updateTargetIr(sourceset: SourcesetIR, targetConfigurationIR: TargetConfigurationIR): TargetConfigurationIR = override fun updateTargetIr(module: ModuleIR, targetConfigurationIR: TargetConfigurationIR): TargetConfigurationIR =
targetConfigurationIR.addWithJavaIntoJvmTarget() targetConfigurationIR.addWithJavaIntoJvmTarget()
override fun TaskRunningContext.getFileTemplates(sourceset: SourcesetIR) = override fun TaskRunningContext.getFileTemplates(module: ModuleIR) =
buildList<FileTemplateDescriptor> { buildList<FileTemplateDescriptorWithPath> {
+FileTemplateDescriptor("$id/main.kt.vm", sourcesPath("main.kt")) +(FileTemplateDescriptor("$id/main.kt.vm", "main.kt".asPath()) asSrcOf SourcesetType.main)
} }
} }
@@ -1,7 +1,6 @@
package org.jetbrains.kotlin.tools.projectWizard.templates package org.jetbrains.kotlin.tools.projectWizard.templates
import org.jetbrains.kotlin.tools.projectWizard.core.Defaults import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.SourcesetType
import org.jetbrains.kotlin.tools.projectWizard.core.div
import java.nio.file.Path import java.nio.file.Path
@@ -9,6 +8,22 @@ import java.nio.file.Path
// Except build files as they will be generated using IR // Except build files as they will be generated using IR
data class FileTemplateDescriptor(val templateId: String, val relativePath: Path) data class FileTemplateDescriptor(val templateId: String, val relativePath: Path)
sealed class FilePath {
abstract val sourcesetType: SourcesetType
}
data class SrcFilePath(override val sourcesetType: SourcesetType) : FilePath()
data class ResourcesFilePath(override val sourcesetType: SourcesetType) : FilePath()
data class FileTemplateDescriptorWithPath(val descriptor: FileTemplateDescriptor, val path: FilePath)
infix fun FileTemplateDescriptor.asResourceOf(sourcesetType: SourcesetType) =
FileTemplateDescriptorWithPath(this, ResourcesFilePath(sourcesetType))
infix fun FileTemplateDescriptor.asSrcOf(sourcesetType: SourcesetType) =
FileTemplateDescriptorWithPath(this, SrcFilePath(sourcesetType))
data class FileTemplate( data class FileTemplate(
val descriptor: FileTemplateDescriptor, val descriptor: FileTemplateDescriptor,
val rootPath: Path, val rootPath: Path,
@@ -16,10 +31,4 @@ data class FileTemplate(
) { ) {
constructor(descriptor: FileTemplateDescriptor, rootPath: Path, vararg data: Pair<String, Any?>) : constructor(descriptor: FileTemplateDescriptor, rootPath: Path, vararg data: Pair<String, Any?>) :
this(descriptor, rootPath, data.toMap()) this(descriptor, rootPath, data.toMap())
} }
fun resourcesPath(fileName: String) =
Defaults.RESOURCES_DIR / fileName
fun sourcesPath(fileName: String) =
Defaults.KOTLIN_DIR / fileName
@@ -23,26 +23,25 @@ class KotlinTestTemplate : Template() {
| More information can be found <a href='https://kotlinlang.org/api/latest/kotlin.test/index.html'>here</a> | More information can be found <a href='https://kotlinlang.org/api/latest/kotlin.test/index.html'>here</a>
""".trimMargin() """.trimMargin()
override val moduleTypes = setOf(ModuleType.common, ModuleType.js, ModuleType.jvm) override val moduleTypes = setOf(ModuleType.common, ModuleType.js, ModuleType.jvm)
override val sourcesetTypes = setOf(SourcesetType.test)
override fun TaskRunningContext.getRequiredLibraries(sourceset: SourcesetIR): List<DependencyIR> = override fun TaskRunningContext.getRequiredLibraries(module: ModuleIR): List<DependencyIR> =
withSettingsOf(sourceset.original) { withSettingsOf(module.originalModule) {
framework.reference.settingValue.dependencyNames.map { dependencyName -> framework.reference.settingValue.dependencyNames.map { dependencyName ->
KotlinArbitraryDependencyIR( KotlinArbitraryDependencyIR(
dependencyName, dependencyName,
isInMppModule = sourceset.original.parent?.kind isInMppModule = module.originalModule.kind
?.let { it == ModuleKind.multiplatform || it == ModuleKind.target } != false, .let { it == ModuleKind.multiplatform || it == ModuleKind.target },
version = KotlinPlugin::version.settingValue, version = KotlinPlugin::version.settingValue,
dependencyType = DependencyType.MAIN dependencyType = DependencyType.MAIN
) )
} }
} }
override fun TaskRunningContext.getFileTemplates(sourceset: SourcesetIR): List<FileTemplateDescriptor> = override fun TaskRunningContext.getFileTemplates(module: ModuleIR): List<FileTemplateDescriptorWithPath> =
withSettingsOf(sourceset.original) { withSettingsOf(module.originalModule) {
buildList { buildList {
if (generateDummyTest.reference.settingValue) { if (generateDummyTest.reference.settingValue) {
+FileTemplateDescriptor("kotlinTestFramework/dummyTest.kt.vm", sourcesPath("Test.kt")) +(FileTemplateDescriptor("kotlinTestFramework/dummyTest.kt.vm", "Test.kt".asPath()) asSrcOf SourcesetType.main)
} }
} }
} }
@@ -54,7 +53,7 @@ class KotlinTestTemplate : Template() {
filter = filter@{ reference, kotlinTestFramework -> filter = filter@{ reference, kotlinTestFramework ->
if (reference !is TemplateSettingReference) return@filter true if (reference !is TemplateSettingReference) return@filter true
val moduleType = reference.sourceset?.containingModuleType val moduleType = reference.module?.configurator?.moduleType
kotlinTestFramework.moduleType == moduleType kotlinTestFramework.moduleType == moduleType
} }
} }
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.tools.projectWizard.templates package org.jetbrains.kotlin.tools.projectWizard.templates
import org.jetbrains.kotlin.tools.projectWizard.core.TaskRunningContext import org.jetbrains.kotlin.tools.projectWizard.core.TaskRunningContext
import org.jetbrains.kotlin.tools.projectWizard.core.asPath
import org.jetbrains.kotlin.tools.projectWizard.core.buildList import org.jetbrains.kotlin.tools.projectWizard.core.buildList
import org.jetbrains.kotlin.tools.projectWizard.core.entity.TemplateSetting import org.jetbrains.kotlin.tools.projectWizard.core.entity.TemplateSetting
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.* import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.*
@@ -25,11 +26,10 @@ class KtorServerTemplate : Template() {
override val title: String = "Ktor-based Server" override val title: String = "Ktor-based Server"
override val htmlDescription: String = title override val htmlDescription: String = title
override val moduleTypes: Set<ModuleType> = setOf(ModuleType.jvm) override val moduleTypes: Set<ModuleType> = setOf(ModuleType.jvm)
override val sourcesetTypes: Set<SourcesetType> = setOf(SourcesetType.main)
override val id: String = "ktorServer" override val id: String = "ktorServer"
override fun TaskRunningContext.getRequiredLibraries(sourceset: SourcesetIR): List<DependencyIR> = override fun TaskRunningContext.getRequiredLibraries(module: ModuleIR): List<DependencyIR> =
withSettingsOf(sourceset.original) { withSettingsOf(module.originalModule) {
buildList { buildList {
+ktorArtifactDependency(serverEngine.reference.settingValue.dependencyName) +ktorArtifactDependency(serverEngine.reference.settingValue.dependencyName)
+ktorArtifactDependency("ktor-html-builder") +ktorArtifactDependency("ktor-html-builder")
@@ -41,17 +41,17 @@ class KtorServerTemplate : Template() {
} }
} }
override fun TaskRunningContext.getIrsToAddToBuildFile(sourceset: SourcesetIR): List<BuildSystemIR> = buildList { override fun TaskRunningContext.getIrsToAddToBuildFile(module: ModuleIR): List<BuildSystemIR> = buildList {
+RepositoryIR(Repositories.KTOR_BINTRAY) +RepositoryIR(Repositories.KTOR_BINTRAY)
+RepositoryIR(DefaultRepository.JCENTER) +RepositoryIR(DefaultRepository.JCENTER)
+runTaskIrs(mainClass = "ServerKt") +runTaskIrs(mainClass = "ServerKt")
} }
override fun updateTargetIr(sourceset: SourcesetIR, targetConfigurationIR: TargetConfigurationIR): TargetConfigurationIR = override fun updateTargetIr(module: ModuleIR, targetConfigurationIR: TargetConfigurationIR): TargetConfigurationIR =
targetConfigurationIR.addWithJavaIntoJvmTarget() targetConfigurationIR.addWithJavaIntoJvmTarget()
override fun TaskRunningContext.getFileTemplates(sourceset: SourcesetIR): List<FileTemplateDescriptor> = listOf( override fun TaskRunningContext.getFileTemplates(module: ModuleIR): List<FileTemplateDescriptorWithPath> = listOf(
FileTemplateDescriptor("$id/server.kt.vm", sourcesPath("server.kt")) FileTemplateDescriptor("$id/server.kt.vm", "server.kt".asPath()) asSrcOf SourcesetType.main
) )
val serverEngine by enumSetting<KtorServerEngine>("Ktor Server", GenerationPhase.PROJECT_GENERATION) val serverEngine by enumSetting<KtorServerEngine>("Ktor Server", GenerationPhase.PROJECT_GENERATION)
@@ -6,7 +6,9 @@
package org.jetbrains.kotlin.tools.projectWizard.templates package org.jetbrains.kotlin.tools.projectWizard.templates
import org.jetbrains.kotlin.tools.projectWizard.core.TaskRunningContext import org.jetbrains.kotlin.tools.projectWizard.core.TaskRunningContext
import org.jetbrains.kotlin.tools.projectWizard.core.asPath
import org.jetbrains.kotlin.tools.projectWizard.core.buildList import org.jetbrains.kotlin.tools.projectWizard.core.buildList
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.ModuleIR
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.SourcesetIR import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.SourcesetIR
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle.multiplatform.NativeTargetInternalIR import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle.multiplatform.NativeTargetInternalIR
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle.multiplatform.TargetConfigurationIR import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle.multiplatform.TargetConfigurationIR
@@ -18,13 +20,12 @@ class NativeConsoleApplicationTemplate : Template() {
override val title: String = "Native Console Application" override val title: String = "Native Console Application"
override val htmlDescription: String = title override val htmlDescription: String = title
override val moduleTypes: Set<ModuleType> = setOf(ModuleType.native) override val moduleTypes: Set<ModuleType> = setOf(ModuleType.native)
override val sourcesetTypes: Set<SourcesetType> = setOf(SourcesetType.main)
override val id: String = "nativeConsoleApp" override val id: String = "nativeConsoleApp"
override fun updateTargetIr(sourceset: SourcesetIR, targetConfigurationIR: TargetConfigurationIR): TargetConfigurationIR = override fun updateTargetIr(module: ModuleIR, targetConfigurationIR: TargetConfigurationIR): TargetConfigurationIR =
targetConfigurationIR.withIrs(NativeTargetInternalIR("main")) targetConfigurationIR.withIrs(NativeTargetInternalIR("main"))
override fun TaskRunningContext.getFileTemplates(sourceset: SourcesetIR): List<FileTemplateDescriptor> = buildList { override fun TaskRunningContext.getFileTemplates(module: ModuleIR): List<FileTemplateDescriptorWithPath> = buildList {
+FileTemplateDescriptor("$id/main.kt.vm", sourcesPath("main.kt")) +(FileTemplateDescriptor("$id/main.kt.vm", "main.kt".asPath()) asSrcOf SourcesetType.main)
} }
} }
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.tools.projectWizard.templates package org.jetbrains.kotlin.tools.projectWizard.templates
import org.jetbrains.kotlin.tools.projectWizard.core.TaskRunningContext import org.jetbrains.kotlin.tools.projectWizard.core.TaskRunningContext
import org.jetbrains.kotlin.tools.projectWizard.core.asPath
import org.jetbrains.kotlin.tools.projectWizard.core.buildList import org.jetbrains.kotlin.tools.projectWizard.core.buildList
import org.jetbrains.kotlin.tools.projectWizard.core.safeAs import org.jetbrains.kotlin.tools.projectWizard.core.safeAs
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.* import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.*
@@ -16,6 +17,7 @@ import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.JsBrowserTar
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.kotlin.ModuleType import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ModuleType
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.DefaultRepository 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.Sourceset import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.Sourceset
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.SourcesetType import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.SourcesetType
import org.jetbrains.kotlin.tools.projectWizard.settings.version.Version import org.jetbrains.kotlin.tools.projectWizard.settings.version.Version
@@ -26,13 +28,12 @@ class SimpleJsClientTemplate : Template() {
override val title: String = "Simple JS client" override val title: String = "Simple JS client"
override val htmlDescription: String = title override val htmlDescription: String = title
override val moduleTypes: Set<ModuleType> = setOf(ModuleType.js) override val moduleTypes: Set<ModuleType> = setOf(ModuleType.js)
override val sourcesetTypes: Set<SourcesetType> = setOf(SourcesetType.main)
override val id: String = "simpleJsClient" override val id: String = "simpleJsClient"
override fun isApplicableTo(sourceset: Sourceset): Boolean = override fun isApplicableTo(module: Module): Boolean =
sourceset.parent?.configurator == JsBrowserTargetConfigurator module.configurator == JsBrowserTargetConfigurator
override fun TaskRunningContext.getRequiredLibraries(sourceset: SourcesetIR): List<DependencyIR> = override fun TaskRunningContext.getRequiredLibraries(module: ModuleIR): List<DependencyIR> =
buildList { buildList {
+ArtifactBasedLibraryDependencyIR( +ArtifactBasedLibraryDependencyIR(
MavenArtifact(DefaultRepository.JCENTER, "org.jetbrains.kotlinx", "kotlinx-html-js"), MavenArtifact(DefaultRepository.JCENTER, "org.jetbrains.kotlinx", "kotlinx-html-js"),
@@ -41,11 +42,11 @@ class SimpleJsClientTemplate : Template() {
) )
} }
override fun TaskRunningContext.getFileTemplates(sourceset: SourcesetIR): List<FileTemplateDescriptor> = listOf( override fun TaskRunningContext.getFileTemplates(module: ModuleIR): List<FileTemplateDescriptorWithPath> = listOf(
FileTemplateDescriptor("$id/client.kt.vm", sourcesPath("client.kt")) FileTemplateDescriptor("$id/client.kt.vm", "client.kt".asPath()) asSrcOf SourcesetType.main
) )
override fun createInterceptors(sourceset: SourcesetIR): List<TemplateInterceptor> = buildList { override fun createInterceptors(module: ModuleIR): List<TemplateInterceptor> = buildList {
+interceptTemplate(KtorServerTemplate()) { +interceptTemplate(KtorServerTemplate()) {
applicableIf { buildFileIR -> applicableIf { buildFileIR ->
val tasks = buildFileIR.irsOfTypeOrNull<GradleConfigureTaskIR>() ?: return@applicableIf false val tasks = buildFileIR.irsOfTypeOrNull<GradleConfigureTaskIR>() ?: return@applicableIf false
@@ -82,7 +83,7 @@ class SimpleJsClientTemplate : Template() {
} }
transformBuildFile { buildFileIR -> transformBuildFile { buildFileIR ->
val jsSourcesetName = sourceset.safeAs<SourcesetModuleIR>()?.targetName ?: return@transformBuildFile null val jsSourcesetName = module.safeAs<SourcesetModuleIR>()?.targetName ?: return@transformBuildFile null
val jvmTarget = buildFileIR.targets.firstOrNull { target -> val jvmTarget = buildFileIR.targets.firstOrNull { target ->
target.safeAs<DefaultTargetConfigurationIR>()?.targetAccess?.type == ModuleSubType.jvm target.safeAs<DefaultTargetConfigurationIR>()?.targetAccess?.type == ModuleSubType.jvm
} as? DefaultTargetConfigurationIR ?: return@transformBuildFile null } as? DefaultTargetConfigurationIR ?: return@transformBuildFile null
@@ -133,12 +134,12 @@ class SimpleJsClientTemplate : Template() {
} }
override fun TaskRunningContext.getIrsToAddToBuildFile(sourceset: SourcesetIR): List<BuildSystemIR> = buildList { override fun TaskRunningContext.getIrsToAddToBuildFile(module: ModuleIR): List<BuildSystemIR> = buildList {
+RepositoryIR(DefaultRepository.JCENTER) +RepositoryIR(DefaultRepository.JCENTER)
if (sourceset is SourcesetModuleIR) { if (module is SourcesetModuleIR) {
+GradleImportIR("org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpack") +GradleImportIR("org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpack")
val taskAccessIR = GradleByNameTaskAccessIR( val taskAccessIR = GradleByNameTaskAccessIR(
"${sourceset.targetName}BrowserWebpack", "${module.name}BrowserWebpack",
WEBPACK_TASK_CLASS WEBPACK_TASK_CLASS
) )
@@ -6,13 +6,11 @@ import org.jetbrains.kotlin.tools.projectWizard.core.*
import org.jetbrains.kotlin.tools.projectWizard.core.entity.* import org.jetbrains.kotlin.tools.projectWizard.core.entity.*
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.* 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.ir.buildsystem.gradle.multiplatform.TargetConfigurationIR
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.TargetConfigurator
import org.jetbrains.kotlin.tools.projectWizard.phases.GenerationPhase import org.jetbrains.kotlin.tools.projectWizard.phases.GenerationPhase
import org.jetbrains.kotlin.tools.projectWizard.plugins.StructurePlugin 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.ModuleType
import org.jetbrains.kotlin.tools.projectWizard.settings.DisplayableSettingItem import org.jetbrains.kotlin.tools.projectWizard.settings.DisplayableSettingItem
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.Sourceset 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.version.Version import org.jetbrains.kotlin.tools.projectWizard.settings.version.Version
import org.jetbrains.kotlin.tools.projectWizard.transformers.interceptors.InterceptionPoint import org.jetbrains.kotlin.tools.projectWizard.transformers.interceptors.InterceptionPoint
import org.jetbrains.kotlin.tools.projectWizard.transformers.interceptors.TemplateInterceptor import org.jetbrains.kotlin.tools.projectWizard.transformers.interceptors.TemplateInterceptor
@@ -25,25 +23,25 @@ interface TemplateEnvironment {
class IdBasedTemplateEnvironment( class IdBasedTemplateEnvironment(
private val template: Template, private val template: Template,
private val sourcesetId: Identificator private val moduleId: Identificator
) : TemplateEnvironment { ) : TemplateEnvironment {
override val <V : Any, T : SettingType<V>> TemplateSetting<V, T>.reference override val <V : Any, T : SettingType<V>> TemplateSetting<V, T>.reference
get() = IdBasedTemplateSettingReference(template, sourcesetId, this) get() = IdBasedTemplateSettingReference(template, moduleId, this)
} }
class SourcesetBasedTemplateEnvironment<Q : Template>( class ModuleBasedTemplateEnvironment<Q : Template>(
val template: Q, val template: Q,
private val sourceset: Sourceset private val module: Module
) : TemplateEnvironment { ) : TemplateEnvironment {
override val <V : Any, T : SettingType<V>> TemplateSetting<V, T>.reference override val <V : Any, T : SettingType<V>> TemplateSetting<V, T>.reference
get() = SourcesetBasedTemplateSettingReference(template, sourceset, this) get() = ModuleBasedTemplateSettingReference(template, module, this)
} }
fun <T> withSettingsOf( fun <T> withSettingsOf(
sourceset: Sourceset, module: Module,
template: Template = sourceset.template!!, template: Template = module.template!!,
function: TemplateEnvironment.() -> T function: TemplateEnvironment.() -> T
): T = function(SourcesetBasedTemplateEnvironment(template, sourceset)) ): T = function(ModuleBasedTemplateEnvironment(template, module))
fun <T> withSettingsOf( fun <T> withSettingsOf(
identificator: Identificator, identificator: Identificator,
@@ -62,38 +60,37 @@ abstract class Template : SettingsOwner {
abstract val title: String abstract val title: String
abstract val htmlDescription: String abstract val htmlDescription: String
abstract val moduleTypes: Set<ModuleType> abstract val moduleTypes: Set<ModuleType>
abstract val sourcesetTypes: Set<SourcesetType>
open fun isApplicableTo(sourceset: Sourceset): Boolean = true open fun isApplicableTo(module: Module): Boolean = true
open val settings: List<TemplateSetting<*, *>> = emptyList() open val settings: List<TemplateSetting<*, *>> = emptyList()
open val interceptionPoints: List<InterceptionPoint<Any>> = emptyList() open val interceptionPoints: List<InterceptionPoint<Any>> = emptyList()
open fun TaskRunningContext.getRequiredLibraries(sourceset: SourcesetIR): List<DependencyIR> = emptyList() open fun TaskRunningContext.getRequiredLibraries(module: ModuleIR): List<DependencyIR> = emptyList()
//TODO: use setting reading context //TODO: use setting reading context
open fun TaskRunningContext.getIrsToAddToBuildFile( open fun TaskRunningContext.getIrsToAddToBuildFile(
sourceset: SourcesetIR module: ModuleIR
): List<BuildSystemIR> = emptyList() ): List<BuildSystemIR> = emptyList()
open fun updateTargetIr( open fun updateTargetIr(
sourceset: SourcesetIR, module: ModuleIR,
targetConfigurationIR: TargetConfigurationIR targetConfigurationIR: TargetConfigurationIR
): TargetConfigurationIR = targetConfigurationIR ): TargetConfigurationIR = targetConfigurationIR
open fun TaskRunningContext.getFileTemplates(sourceset: SourcesetIR): List<FileTemplateDescriptor> = emptyList() open fun TaskRunningContext.getFileTemplates(module: ModuleIR): List<FileTemplateDescriptorWithPath> = emptyList()
open fun createInterceptors(sourceset: SourcesetIR): List<TemplateInterceptor> = emptyList() open fun createInterceptors(module: ModuleIR): List<TemplateInterceptor> = emptyList()
fun TaskRunningContext.applyToSourceset( fun TaskRunningContext.applyToSourceset(
sourceset: SourcesetIR module: ModuleIR
): TaskResult<TemplateApplicationResult> { ): TaskResult<TemplateApplicationResult> {
val librariesToAdd = getRequiredLibraries(sourceset) val librariesToAdd = getRequiredLibraries(module)
val irsToAddToBuildFile = getIrsToAddToBuildFile(sourceset) val irsToAddToBuildFile = getIrsToAddToBuildFile(module)
val targetsUpdater = when (sourceset) { val targetsUpdater = when (module) {
is SourcesetModuleIR -> { target: TargetConfigurationIR -> is SourcesetModuleIR -> { target: TargetConfigurationIR ->
if (target.targetName == sourceset.targetName) updateTargetIr(sourceset, target) if (target.targetName == module.name) updateTargetIr(module, target)
else target else target
} }
else -> idFunction() else -> idFunction()
@@ -103,8 +100,8 @@ abstract class Template : SettingsOwner {
return result.asSuccess() return result.asSuccess()
} }
fun TaskRunningContext.settingsAsMap(sourceset: Sourceset): Map<String, Any> = fun TaskRunningContext.settingsAsMap(module: Module): Map<String, Any> =
withSettingsOf(sourceset) { withSettingsOf(module) {
settings.associate { setting -> settings.associate { setting ->
setting.path to setting.reference.settingValue setting.path to setting.reference.settingValue
} }
@@ -233,18 +230,17 @@ abstract class Template : SettingsOwner {
} }
} }
fun Template.settings(sourceset: Sourceset) = withSettingsOf(sourceset) { fun Template.settings(module: Module) = withSettingsOf(module) {
settings.map { it.reference } settings.map { it.reference }
} }
fun TaskRunningContext.applyTemplateToSourceset( fun TaskRunningContext.applyTemplateToModule(
template: Template?, template: Template?,
sourceset: SourcesetIR, module: ModuleIR
templateEngine: TemplateEngine
): TaskResult<TemplateApplicationResult> = when (template) { ): TaskResult<TemplateApplicationResult> = when (template) {
null -> TemplateApplicationResult.EMPTY.asSuccess() null -> TemplateApplicationResult.EMPTY.asSuccess()
else -> with(template) { else -> with(template) {
applyToSourceset(sourceset) applyToSourceset(module)
} }
} }
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.tools.projectWizard.transformers.interceptors
import org.jetbrains.kotlin.tools.projectWizard.Identificator import org.jetbrains.kotlin.tools.projectWizard.Identificator
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.BuildFileIR import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.BuildFileIR
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.sourcesets
import org.jetbrains.kotlin.tools.projectWizard.templates.Template import org.jetbrains.kotlin.tools.projectWizard.templates.Template
import org.jetbrains.kotlin.tools.projectWizard.transformers.Predicate import org.jetbrains.kotlin.tools.projectWizard.transformers.Predicate
import org.jetbrains.kotlin.tools.projectWizard.transformers.TransformerFunction import org.jetbrains.kotlin.tools.projectWizard.transformers.TransformerFunction
@@ -19,7 +18,7 @@ typealias SourcesetInterceptionPointValues = Map<Identificator, InterceptionPoin
data class TemplateInterceptionApplicationState( data class TemplateInterceptionApplicationState(
val buildFileIR: BuildFileIR, val buildFileIR: BuildFileIR,
val sourcesetToSettings: SourcesetInterceptionPointValues val moduleToSettings: SourcesetInterceptionPointValues
) )
data class TemplateInterceptor( data class TemplateInterceptor(
@@ -31,14 +30,14 @@ data class TemplateInterceptor(
fun applyTo(state: TemplateInterceptionApplicationState): TemplateInterceptionApplicationState { fun applyTo(state: TemplateInterceptionApplicationState): TemplateInterceptionApplicationState {
if (applicabilityCheckers.any { checker -> !checker(state.buildFileIR) }) return state if (applicabilityCheckers.any { checker -> !checker(state.buildFileIR) }) return state
val sourcesetsWithTemplate = state.buildFileIR.sourcesets.filter { it.template?.id == template.id } val modulesWithTemplate = state.buildFileIR.modules.modules.filter { it.template?.id == template.id }
if (sourcesetsWithTemplate.isEmpty()) return state if (modulesWithTemplate.isEmpty()) return state
val transformedBuildFile = applyBuildFileTransformers(state.buildFileIR) val transformedBuildFile = applyBuildFileTransformers(state.buildFileIR)
val mutableValues = state.sourcesetToSettings.toMutableMap() val mutableValues = state.moduleToSettings.toMutableMap()
for (sourceset in sourcesetsWithTemplate) { for (module in modulesWithTemplate) {
mutableValues.compute(sourceset.original.identificator) { _, values -> mutableValues.compute(module.originalModule.identificator) { _, values ->
applyInterceptionPointModifiers(values.orEmpty()) applyInterceptionPointModifiers(values.orEmpty())
} }
} }