Get rid of reflection in new project wizard core: manually specify properties in plugins

This commit is contained in:
aleksandrina-streltsova
2020-07-22 13:56:41 +03:00
committed by Kirill Shmakov
parent cc35529b9a
commit 63e2d771b3
55 changed files with 998 additions and 1009 deletions
@@ -4,7 +4,6 @@ import com.intellij.facet.impl.ui.libraries.LibraryOptionsPanel
import com.intellij.framework.library.FrameworkLibraryVersionFilter
import com.intellij.openapi.project.Project
import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.roots.ui.configuration.libraries.CustomLibraryDescription
import com.intellij.openapi.roots.ui.configuration.projectRoot.LibrariesContainer
import com.intellij.openapi.roots.ui.configuration.projectRoot.LibrariesContainerFactory
import org.jetbrains.kotlin.idea.framework.JavaRuntimeLibraryDescription
@@ -43,14 +42,14 @@ class IdeWizard(
)
var jdk: Sdk? = null
var projectPath by setting(StructurePlugin::projectPath.reference)
var projectName by setting(StructurePlugin::name.reference)
var projectPath by setting(StructurePlugin.projectPath.reference)
var projectName by setting(StructurePlugin.name.reference)
var groupId by setting(StructurePlugin::groupId.reference)
var artifactId by setting(StructurePlugin::artifactId.reference)
var buildSystemType by setting(BuildSystemPlugin::type.reference)
var groupId by setting(StructurePlugin.groupId.reference)
var artifactId by setting(StructurePlugin.artifactId.reference)
var buildSystemType by setting(BuildSystemPlugin.type.reference)
var projectTemplate by setting(ProjectTemplatesPlugin::template.reference)
var projectTemplate by setting(ProjectTemplatesPlugin.template.reference)
private fun <V : Any, T : SettingType<V>> setting(reference: SettingReference<V, T>) =
object : ReadWriteProperty<Any?, V?> {
@@ -3,7 +3,6 @@ package org.jetbrains.kotlin.tools.projectWizard.wizard
import com.intellij.ide.RecentProjectsManager
import com.intellij.ide.actions.NewProjectAction
import com.intellij.ide.impl.NewProjectUtil
import com.intellij.ide.projectWizard.NewProjectWizard
import com.intellij.ide.util.projectWizard.*
import com.intellij.ide.wizard.AbstractWizard
import com.intellij.openapi.Disposable
@@ -14,11 +13,9 @@ import com.intellij.openapi.module.ModuleType
import com.intellij.openapi.options.ConfigurationException
import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.ProjectManager
import com.intellij.openapi.roots.ui.configuration.ModulesProvider
import com.intellij.openapi.ui.Messages
import com.intellij.util.SystemProperties
import org.jetbrains.kotlin.idea.configuration.ExperimentalFeatures
import org.jetbrains.kotlin.idea.framework.KotlinTemplatesFactory
import org.jetbrains.kotlin.idea.projectWizard.ProjectCreationStats
import org.jetbrains.kotlin.idea.projectWizard.UiEditorUsageStats
@@ -201,12 +198,12 @@ class ModuleNewWizardFirstStep(wizard: IdeWizard) : WizardStep(wizard, Generatio
val suggestedProjectParentLocation = suggestProjectLocation()
val suggestedProjectName = ProjectWizardUtil.findNonExistingFileName(suggestedProjectParentLocation, "untitled", "")
wizard.context.writeSettings {
StructurePlugin::name.reference.setValue(suggestedProjectName)
StructurePlugin::projectPath.reference.setValue(suggestedProjectParentLocation / suggestedProjectName)
StructurePlugin::artifactId.reference.setValue(suggestedProjectName)
StructurePlugin.name.reference.setValue(suggestedProjectName)
StructurePlugin.projectPath.reference.setValue(suggestedProjectParentLocation / suggestedProjectName)
StructurePlugin.artifactId.reference.setValue(suggestedProjectName)
if (StructurePlugin::groupId.reference.notRequiredSettingValue == null) {
StructurePlugin::groupId.reference.setValue(suggestGroupId())
if (StructurePlugin.groupId.notRequiredSettingValue == null) {
StructurePlugin.groupId.reference.setValue(suggestGroupId())
}
}
}
@@ -6,10 +6,8 @@ import org.jetbrains.kotlin.tools.projectWizard.core.Reader
import org.jetbrains.kotlin.tools.projectWizard.core.SettingsWriter
import org.jetbrains.kotlin.tools.projectWizard.core.Writer
import org.jetbrains.kotlin.tools.projectWizard.core.entity.ValidationResult
import org.jetbrains.kotlin.tools.projectWizard.core.entity.settings.PluginSettingPropertyReference
import org.jetbrains.kotlin.tools.projectWizard.core.entity.settings.SettingReference
import org.jetbrains.kotlin.tools.projectWizard.core.entity.settings.SettingType
import org.jetbrains.kotlin.tools.projectWizard.core.entity.settings.reference
abstract class Component : Displayable, ErrorNavigatable {
private val subComponents = mutableListOf<Component>()
@@ -45,10 +43,6 @@ abstract class DynamicComponent(private val context: Context) : Component() {
value?.let { setValue(it) }
}
inline val <V : Any, reified T : SettingType<V>> PluginSettingPropertyReference<V, T>.value: V?
get() = reference.value
init {
write {
eventManager.addSettingUpdaterEventListener { reference ->
@@ -29,7 +29,7 @@ import javax.swing.JComponent
class BuildSystemTypeSettingComponent(
context: Context
) : SettingComponent<BuildSystemType, DropDownSettingType<BuildSystemType>>(
BuildSystemPlugin::type.reference,
BuildSystemPlugin.type.reference,
context
) {
@@ -12,7 +12,6 @@ import com.intellij.ui.layout.panel
import com.intellij.util.ui.JBUI
import com.intellij.util.ui.components.BorderLayoutPanel
import org.jetbrains.kotlin.tools.projectWizard.core.Context
import org.jetbrains.kotlin.tools.projectWizard.core.entity.path
import org.jetbrains.kotlin.tools.projectWizard.core.entity.settings.SettingReference
import org.jetbrains.kotlin.tools.projectWizard.core.entity.settings.reference
import org.jetbrains.kotlin.tools.projectWizard.plugins.StructurePlugin
@@ -53,8 +52,8 @@ class ProjectSettingsComponent(ideWizard: IdeWizard) : DynamicComponent(ideWizar
private val nameAndLocationComponent = TitledComponentsList(
listOf(
StructurePlugin::name.reference.createSettingComponent(context),
StructurePlugin::projectPath.reference.createSettingComponent(context),
StructurePlugin.name.reference.createSettingComponent(context),
StructurePlugin.projectPath.reference.createSettingComponent(context),
projectTemplateComponent,
buildSystemSetting,
jdkComponent
@@ -84,17 +83,17 @@ class ProjectSettingsComponent(ideWizard: IdeWizard) : DynamicComponent(ideWizar
override fun onValueUpdated(reference: SettingReference<*, *>?) {
super.onValueUpdated(reference)
when (reference?.path) {
StructurePlugin::name.path -> {
val isNameValid = read { StructurePlugin::name.reference.validate().isOk }
StructurePlugin.name.path -> {
val isNameValid = read { StructurePlugin.name.reference.validate().isOk }
if (isNameValid) {
tryUpdateLocationByProjectName()
tryArtifactIdByProjectName()
}
}
StructurePlugin::artifactId.path -> {
StructurePlugin.artifactId.path -> {
artifactIdWasUpdatedByHand = true
}
StructurePlugin::projectPath.path -> {
StructurePlugin.projectPath.path -> {
locationWasUpdatedByHand = true
}
}
@@ -102,9 +101,9 @@ class ProjectSettingsComponent(ideWizard: IdeWizard) : DynamicComponent(ideWizar
private fun tryUpdateLocationByProjectName() {
if (!locationWasUpdatedByHand) {
val location = read { StructurePlugin::projectPath.settingValue }
val location = read { StructurePlugin.projectPath.settingValue }
if (location.parent != null) modify {
StructurePlugin::projectPath.reference.setValue(location.parent.resolve(StructurePlugin::name.settingValue))
StructurePlugin.projectPath.reference.setValue(location.parent.resolve(StructurePlugin.name.settingValue))
locationWasUpdatedByHand = false
}
}
@@ -112,7 +111,7 @@ class ProjectSettingsComponent(ideWizard: IdeWizard) : DynamicComponent(ideWizar
private fun tryArtifactIdByProjectName() {
if (!artifactIdWasUpdatedByHand) modify {
StructurePlugin::artifactId.reference.setValue(StructurePlugin::name.settingValue)
StructurePlugin.artifactId.reference.setValue(StructurePlugin.name.settingValue)
artifactIdWasUpdatedByHand = false
}
}
@@ -124,7 +123,7 @@ class BuildSystemAdditionalSettingsComponent(ideWizard: IdeWizard) : DynamicComp
override fun onValueUpdated(reference: SettingReference<*, *>?) {
super.onValueUpdated(reference)
if (reference == BuildSystemPlugin::type.reference) {
if (reference == BuildSystemPlugin.type.reference) {
updateBuildSystemComponent()
}
}
@@ -135,7 +134,7 @@ class BuildSystemAdditionalSettingsComponent(ideWizard: IdeWizard) : DynamicComp
}
private fun updateBuildSystemComponent() {
val buildSystemType = read { BuildSystemPlugin::type.settingValue() }
val buildSystemType = read { BuildSystemPlugin.type.settingValue }
val state = buildSystemType.state()
section.updateTitleAndComponent(state.sectionTitle, state.component)
}
@@ -162,9 +161,9 @@ class BuildSystemAdditionalSettingsComponent(ideWizard: IdeWizard) : DynamicComp
private class PomSettingsComponent(context: Context) : TitledComponentsList(
listOf(
StructurePlugin::groupId.reference.createSettingComponent(context),
StructurePlugin::artifactId.reference.createSettingComponent(context),
StructurePlugin::version.reference.createSettingComponent(context)
StructurePlugin.groupId.reference.createSettingComponent(context),
StructurePlugin.artifactId.reference.createSettingComponent(context),
StructurePlugin.version.reference.createSettingComponent(context)
),
context,
stretchY = true
@@ -257,7 +256,7 @@ class ProjectPreviewComponent(context: Context) : DynamicComponent(context) {
override fun onValueUpdated(reference: SettingReference<*, *>?) {
super.onValueUpdated(reference)
if (reference == ProjectTemplatesPlugin::template.reference) {
if (reference == ProjectTemplatesPlugin.template.reference) {
modulesEditorComponent.updateModel()
}
}
@@ -23,7 +23,7 @@ import javax.swing.JComponent
class ProjectTemplateSettingComponent(
context: Context
) : SettingComponent<ProjectTemplate, DropDownSettingType<ProjectTemplate>>(
ProjectTemplatesPlugin::template.reference,
ProjectTemplatesPlugin.template.reference,
context
) {
override val validationIndicator: ValidationIndicator? get() = null
@@ -58,7 +58,7 @@ class ProjectTemplateSettingComponent(
override fun onValueUpdated(reference: SettingReference<*, *>?) {
super.onValueUpdated(reference)
if (reference == ProjectTemplatesPlugin::template.reference) {
if (reference == ProjectTemplatesPlugin.template.reference) {
applySelectedTemplate()
value?.let { template ->
list.setSelectedValue(template, true)
@@ -61,7 +61,7 @@ class ModuleDependenciesComponent(
}
private fun possibleDependencies(): List<Module> =
read { KotlinPlugin::modules.settingValue }.withAllSubModules().toMutableList().apply {
read { KotlinPlugin.modules.settingValue }.withAllSubModules().toMutableList().apply {
module?.let(::remove)
removeAll(
module
@@ -90,7 +90,7 @@ private class ModuleNameComponent(context: Context, private val module: Module)
override fun onInit() {
super.onInit()
val isSingleRootMode = read { KotlinPlugin::modules.settingValue }.size == 1
val isSingleRootMode = read { KotlinPlugin.modules.settingValue }.size == 1
when {
isSingleRootMode && module.isRootModule -> {
textField.disable(KotlinNewProjectWizardUIBundle.message("module.settings.name.same.as.project"))
@@ -168,7 +168,7 @@ private object NoneTemplate : Template() {
}
fun Reader.availableTemplatesFor(module: Module) =
TemplatesPlugin::templates.propertyValue.values.filter { template ->
TemplatesPlugin.templates.propertyValue.values.filter { template ->
module.configurator.moduleType in template.moduleTypes
}
@@ -26,14 +26,14 @@ class ModulesEditorComponent(
needBorder: Boolean,
private val editable: Boolean,
oneEntrySelected: (data: DisplayableSettingItem?) -> Unit
) : SettingComponent<List<Module>, ListSettingType<Module>>(KotlinPlugin::modules.reference, context) {
) : SettingComponent<List<Module>, ListSettingType<Module>>(KotlinPlugin.modules.reference, context) {
private val tree: ModulesEditorTree =
ModulesEditorTree(
onSelected = { oneEntrySelected(it) },
context = context,
isTreeEditable = editable,
addModule = { component ->
val isMppProject = KotlinPlugin::projectKind.value == ProjectKind.Singleplatform
val isMppProject = KotlinPlugin.projectKind.reference.value == ProjectKind.Singleplatform
moduleCreator.create(
target = null, // The empty tree case
allowMultiplatform = isMppProject,
@@ -77,7 +77,7 @@ class ModulesEditorComponent(
moduleCreator = moduleCreator,
model = model,
getModules = { value ?: emptyList() },
isMultiplatformProject = { KotlinPlugin::projectKind.value != ProjectKind.Singleplatform }
isMultiplatformProject = { KotlinPlugin.projectKind.reference.value != ProjectKind.Singleplatform }
) else null
override val component: JComponent by lazy(LazyThreadSafetyMode.NONE) {
@@ -59,7 +59,7 @@ class GradleProjectImportingTestWizardService(private val project: Project) : Pr
return importingErrorMessage?.let { message ->
Failure(
ProjectImportingError(
reader { KotlinPlugin::version.propertyValue.version.toString() },
reader { KotlinPlugin.version.propertyValue.version.toString() },
message,
)
)
@@ -32,7 +32,7 @@ class YamlWizard(
context.writeSettings {
settingsValuesFromYaml.forEach { (reference, value) -> reference.setValue(value) }
StructurePlugin::projectPath.reference.setValue(projectPath)
StructurePlugin.projectPath.reference.setValue(projectPath)
}
super.apply(services, phases, onTaskExecuting)
@@ -49,7 +49,7 @@ fun Reader.parseYaml(
yaml: String,
pluginSettings: List<PluginSetting<*, *>>
): TaskResult<Map<SettingReference<*, *>, Any>> {
val parsingData = ParsingState(TemplatesPlugin::templates.propertyValue, emptyMap())
val parsingData = ParsingState(TemplatesPlugin.templates.propertyValue, emptyMap())
val yamlParser = YamlSettingsParser(pluginSettings, parsingData)
return yamlParser.parseYamlText(yaml)
}
@@ -43,11 +43,11 @@ class ProjectTemplateBasedTestWizard(
super.apply(services, setOf(GenerationPhase.PREPARE), onTaskExecuting).ensure()
context.writeSettings {
applyProjectTemplate(projectTemplate)
BuildSystemPlugin::type.reference.setValue(buildSystem.buildSystemType)
StructurePlugin::projectPath.reference.setValue(projectDirectory)
StructurePlugin::name.reference.setValue(projectTemplate.id)
StructurePlugin::groupId.reference.setValue(GROUP_ID)
StructurePlugin::artifactId.reference.setValue(ARTIFACT_ID)
BuildSystemPlugin.type.reference.setValue(buildSystem.buildSystemType)
StructurePlugin.projectPath.reference.setValue(projectDirectory)
StructurePlugin.name.reference.setValue(projectTemplate.id)
StructurePlugin.groupId.reference.setValue(GROUP_ID)
StructurePlugin.artifactId.reference.setValue(ARTIFACT_ID)
}
applyAdditionalSettingsFromYaml().ensure()
@@ -10,6 +10,7 @@ import kotlin.properties.ReadOnlyProperty
interface SettingsOwner {
fun <V : Any, T : SettingType<V>> settingDelegate(
prefix: String,
create: (path: String) -> SettingBuilder<V, T>
): ReadOnlyProperty<Any, Setting<V, T>>
@@ -21,24 +22,27 @@ interface SettingsOwner {
title: String,
neededAtPhase: GenerationPhase,
parser: Parser<V>,
prefix: String = "",
init: DropDownSettingType.Builder<V>.() -> Unit = {}
): ReadOnlyProperty<Any, Setting<V, DropDownSettingType<V>>> = settingDelegate { path ->
): ReadOnlyProperty<Any, Setting<V, DropDownSettingType<V>>> = settingDelegate(prefix) { path ->
DropDownSettingType.Builder(path, title, neededAtPhase, parser).apply(init)
}
fun stringSetting(
title: String,
neededAtPhase: GenerationPhase,
prefix: String = "",
init: StringSettingType.Builder.() -> Unit = {}
) = settingDelegate { path ->
) = settingDelegate(prefix) { path ->
StringSettingType.Builder(path, title, neededAtPhase).apply(init)
}
fun booleanSetting(
title: String,
neededAtPhase: GenerationPhase,
prefix: String = "",
init: BooleanSettingType.Builder.() -> Unit = {}
) = settingDelegate { path ->
) = settingDelegate(prefix) { path ->
BooleanSettingType.Builder(path, title, neededAtPhase).apply(init)
}
@@ -46,16 +50,18 @@ interface SettingsOwner {
title: String,
neededAtPhase: GenerationPhase,
parser: Parser<V>,
prefix: String = "",
init: ValueSettingType.Builder<V>.() -> Unit = {}
) = settingDelegate { path ->
) = settingDelegate(prefix) { path ->
ValueSettingType.Builder(path, title, neededAtPhase, parser).apply(init)
}
fun versionSetting(
title: String,
neededAtPhase: GenerationPhase,
prefix: String = "",
init: VersionSettingType.Builder.() -> Unit = {}
) = settingDelegate { path ->
) = settingDelegate(prefix) { path ->
VersionSettingType.Builder(path, title, neededAtPhase).apply(init)
}
@@ -63,16 +69,18 @@ interface SettingsOwner {
title: String,
neededAtPhase: GenerationPhase,
parser: Parser<V>,
prefix: String = "",
init: ListSettingType.Builder<V>.() -> Unit = {}
) = settingDelegate { path ->
) = settingDelegate(prefix) { path ->
ListSettingType.Builder(path, title, neededAtPhase, parser).apply(init)
}
fun pathSetting(
title: String,
neededAtPhase: GenerationPhase,
prefix: String = "",
init: PathSettingType.Builder.() -> Unit = {}
) = settingDelegate { path ->
) = settingDelegate(prefix) { path ->
PathSettingType.Builder(path, title, neededAtPhase).apply(init)
}
}
@@ -81,8 +89,9 @@ interface SettingsOwner {
inline fun <reified E> SettingsOwner.enumSettingImpl(
title: String,
neededAtPhase: GenerationPhase,
prefix: String = "",
crossinline init: DropDownSettingType.Builder<E>.() -> Unit = {}
) where E : Enum<E>, E : DisplayableSettingItem = dropDownSetting<E>(title, neededAtPhase, enumParser()) {
) where E : Enum<E>, E : DisplayableSettingItem = dropDownSetting<E>(title, neededAtPhase, enumParser(), prefix) {
values = enumValues<E>().asList()
//
init()
@@ -6,19 +6,14 @@ 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 kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KClass
import kotlin.reflect.KProperty1
import kotlin.reflect.full.isSubclassOf
import kotlin.reflect.full.memberProperties
class Context private constructor(
private val servicesManager: ServicesManager,
val servicesManager: ServicesManager,
private val isUnitTestMode: Boolean,
private val settingContext: SettingContext,
private val propertyContext: PropertyContext,
private val taskContext: TaskContext
private val propertyContext: PropertyContext
) {
private lateinit var plugins: List<Plugin>
@@ -47,8 +42,7 @@ class Context private constructor(
servicesManager,
isUnitTestMode,
SettingContext(),
PropertyContext(),
TaskContext()
PropertyContext()
) {
plugins = pluginsCreator(this).onEach(::initPlugin)
}
@@ -58,50 +52,17 @@ class Context private constructor(
servicesManager.withAdditionalServices(services),
isUnitTestMode,
settingContext,
propertyContext,
taskContext
propertyContext
).also {
it.plugins = plugins
}
fun <V : Any, T : SettingType<V>> pluginSettingDelegate(
create: (path: String) -> SettingBuilder<V, T>
): ReadOnlyProperty<Any, PluginSetting<V, T>> =
settingContext.settingDelegate(create)
fun <T : Any> propertyDelegate(
init: Property.Builder<T>.() -> Unit,
defaultValue: T
) = entityDelegate(propertyContext) { name ->
Property.Builder(name, defaultValue).apply(init).build()
}
fun pipelineTaskDelegate(
phase: GenerationPhase,
init: PipelineTask.Builder.() -> Unit
) = entityDelegate(taskContext) { name ->
PipelineTask.Builder(name, phase).apply(init).build()
}
fun <A, B : Any> task1Delegate(
init: Task1.Builder<A, B>.() -> Unit
) = entityDelegate(taskContext) { name ->
Task1.Builder<A, B>(name).apply(init).build()
}
private fun initPlugin(plugin: Plugin) {
for (entityReference in plugin::class.memberProperties) {
val type = entityReference.returnType.classifier.safeAs<KClass<*>>() ?: continue
if (type.isSubclassOf(Entity::class)) {
when (val entity = entityReference.getter.call(plugin)) {
is Property<*> -> {
@Suppress("UNCHECKED_CAST")
propertyContext[entityReference as PropertyReference<Any>] = entity.defaultValue
}
}
}
for (property in plugin.properties) {
propertyContext[property] = property.defaultValue
}
for (setting in plugin.settings) {
settingContext.setPluginSetting(setting.reference, setting)
}
}
@@ -110,17 +71,14 @@ class Context private constructor(
get() = plugins
.flatMap { it.pipelineTasks }
private fun task(reference: PipelineTaskReference) =
taskContext.getEntity(reference) as? PipelineTask ?: error(reference.path)
private val dependencyList: Map<PipelineTask, List<PipelineTask>>
get() {
val dependeeMap = pipelineLineTasks.flatMap { task ->
task.after.map { after -> task to task(after) }
task.after.map { after -> task to after }
}
val dependencyMap = pipelineLineTasks.flatMap { task ->
task.before.map { before -> task(before) to task }
task.before.map { before -> before to task }
}
return (dependeeMap + dependencyMap)
@@ -151,18 +109,17 @@ class Context private constructor(
fun <S : WizardService> serviceByClass(klass: KClass<S>, filter: (S) -> Boolean = { true }): S =
servicesManager.serviceByClass(klass, filter) ?: error("Service ${klass.simpleName} was not found")
@Suppress("UNCHECKED_CAST")
val <T : Any> PropertyReference<T>.propertyValue: T
get() = propertyContext[this] as T
val <T : Any> Property<T>.propertyValue: T
get() = propertyContext[this] ?: error("No value is present for property `$this`")
val <V : Any, T : SettingType<V>> SettingReference<V, T>.settingValue: V
get() = settingContext[this] ?: error("No value is present for setting `$this`")
inline val <reified V : Any> KProperty1<out Plugin, PluginSetting<V, SettingType<V>>>.settingValue: V
get() = reference.settingValue
val <V : Any> PluginSetting<V, SettingType<V>>.settingValue: V
get() = settingContext[this.reference] ?: error("No value is present for setting `$this`")
inline fun <reified V : Any> KProperty1<out Plugin, PluginSetting<V, SettingType<V>>>.settingValue(): V =
this.reference.settingValue
val <V : Any> PluginSetting<V, SettingType<V>>.notRequiredSettingValue: V?
get() = settingContext[this.reference]
fun <V : Any, T : SettingType<V>> SettingReference<V, T>.settingValue(): V =
settingContext[this] ?: error("No value is present for setting `$this`")
@@ -207,24 +164,23 @@ class Context private constructor(
val eventManager: EventManager
get() = settingContext.eventManager
fun <A, B : Any> Task1Reference<A, B>.execute(value: A): TaskResult<B> {
fun <A, B : Any> Task1<A, B>.execute(value: A): TaskResult<B> {
@Suppress("UNCHECKED_CAST")
val task = taskContext.getEntity(this) as Task1<A, B>
return task.action(this@Writer, value)
return action(this@Writer, value)
}
fun <T : Any> PropertyReference<T>.update(
fun <T : Any> Property<T>.update(
updater: suspend ComputeContext<*>.(T) -> TaskResult<T>
): TaskResult<Unit> = compute {
val (newValue) = updater(propertyValue)
propertyContext[this@update] = newValue
}
fun <T : Any> PropertyReference<List<T>>.addValues(
fun <T : Any> Property<List<T>>.addValues(
vararg values: T
): TaskResult<Unit> = update { oldValues -> success(oldValues + values) }
fun <T : Any> PropertyReference<List<T>>.addValues(
fun <T : Any> Property<List<T>>.addValues(
values: List<T>
): TaskResult<Unit> = update { oldValues -> success(oldValues + values) }
@@ -6,7 +6,6 @@ import org.jetbrains.kotlin.tools.projectWizard.settings.DisplayableSettingItem
import org.jetbrains.kotlin.tools.projectWizard.templates.Template
import java.nio.file.Paths
import kotlin.reflect.KClass
import kotlin.reflect.full.isSubclassOf
data class ParsingState(
val idToTemplate: Map<String, Template>,
@@ -87,10 +86,6 @@ fun <T : Any> valueParserM(parser: suspend ParsingContext.(value: Any?, path: St
}
}
inline fun <reified T : Any> valueParser() = valueParser { value, path ->
value.parseAs(path, T::class).get()
}
fun Any?.classMismatchError(@NonNls path: String, expected: KClass<*>): ParseError {
val classpath = this?.let { it::class.simpleName } ?: "null"
return ParseError("Expected ${expected.simpleName!!} for `$path` but $classpath was found")
@@ -100,11 +95,6 @@ inline fun <reified V : Any> Any?.parseAs(@NonNls path: String) =
safeAs<V>().toResult { classMismatchError(path, V::class) }
inline fun <reified T : Any> Any?.parseAs(@NonNls path: String, klass: KClass<T>): TaskResult<T> =
this?.takeIf { it::class.isSubclassOf(klass) }?.safeAs<T>()
.toResult { classMismatchError(path, klass) }
inline fun <reified V : Any> Map<*, *>.parseValue(@NonNls path: String, @NonNls name: String) =
get(name).parseAs<V>("$path.$name")
@@ -124,13 +114,6 @@ inline fun <reified V : Any, R : Any> Map<*, *>.parseValue(
}
}
inline fun <reified T : Any> Map<*, *>.parseValue(
@NonNls path: String,
@NonNls name: String,
klass: KClass<T>
) = get(path).parseAs("$path.$name", klass)
fun <R : Any> Map<*, *>.parseValue(
context: ParsingContext,
@NonNls path: String,
@@ -9,163 +9,163 @@ import org.jetbrains.kotlin.tools.projectWizard.settings.DisplayableSettingItem
import org.jetbrains.kotlin.tools.projectWizard.settings.version.Version
import java.nio.file.Path
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KClass
import kotlin.reflect.full.isSubclassOf
typealias PluginReference = KClass<out Plugin>
typealias PluginsCreator = (Context) -> List<Plugin>
abstract class Plugin(override val context: Context) : EntityBase(),
SettingsOwner,
ContextOwner,
EntitiesOwnerDescriptor,
EntitiesOwner<Plugin> {
override val descriptor get() = this
override val id: String get() = path
override fun <V : Any, T : SettingType<V>> settingDelegate(
create: (path: String) -> SettingBuilder<V, T>
): ReadOnlyProperty<Any, PluginSetting<V, T>> = context.pluginSettingDelegate(create)
val reference = this::class
abstract override val path: String
abstract val properties: List<Property<*>>
abstract val settings: List<PluginSetting<*, *>>
abstract val pipelineTasks: List<PipelineTask>
fun pipelineTask(phase: GenerationPhase, init: PipelineTask.Builder.() -> Unit) =
context.pipelineTaskDelegate(phase, init)
companion object : SettingsOwner {
fun pipelineTask(
prefix: String,
phase: GenerationPhase,
init: PipelineTask.Builder.() -> Unit
): ReadOnlyProperty<Any, PipelineTask> =
cached { name -> PipelineTask.Builder(withPrefix(prefix, name), phase).apply(init).build() }
fun <A, B : Any> task1(init: Task1.Builder<A, B>.() -> Unit) =
context.task1Delegate(init)
fun <A, B : Any> task1(
prefix: String,
init: Task1.Builder<A, B>.() -> Unit
): ReadOnlyProperty<Any, Task1<A, B>> = cached { name -> Task1.Builder<A, B>(withPrefix(prefix, name)).apply(init).build() }
fun <T : Any> property(defaultValue: T, init: Property.Builder<T>.() -> Unit = {}) =
context.propertyDelegate(init, defaultValue)
fun <T : Any> property(
prefix: String,
defaultValue: T,
init: Property.Builder<T>.() -> Unit = {}
): ReadOnlyProperty<Any, Property<T>> =
cached { name -> Property.Builder(withPrefix(prefix, name), defaultValue).apply(init).build() }
fun <T : Any> listProperty(vararg defaultValues: T, init: Property.Builder<List<T>>.() -> Unit = {}) =
property(defaultValues.toList(), init)
fun <T : Any> listProperty(prefix: String, vararg defaultValues: T, init: Property.Builder<List<T>>.() -> Unit = {}) =
property(prefix, defaultValues.toList(), init)
private fun withPrefix(name: String, prefix: String): String = if (prefix.isNotEmpty()) "$prefix.$name" else name
// setting types
override fun <V : Any, T : SettingType<V>> settingDelegate(
prefix: String,
create: (path: String) -> SettingBuilder<V, T>
): ReadOnlyProperty<Any, PluginSetting<V, T>> = cached { name -> PluginSetting(create(withPrefix(name, prefix)).buildInternal()) }
@Suppress("UNCHECKED_CAST")
final override fun <V : DisplayableSettingItem> dropDownSetting(
title: String,
neededAtPhase: GenerationPhase,
parser: Parser<V>,
init: DropDownSettingType.Builder<V>.() -> Unit
): ReadOnlyProperty<Any, PluginSetting<V, DropDownSettingType<V>>> =
super.dropDownSetting(
title,
neededAtPhase,
parser,
init
) as ReadOnlyProperty<Any, PluginSetting<V, DropDownSettingType<V>>>
// setting types
@Suppress("UNCHECKED_CAST")
final override fun stringSetting(
title: String,
neededAtPhase: GenerationPhase,
init: StringSettingType.Builder.() -> Unit
): ReadOnlyProperty<Any, PluginSetting<String, StringSettingType>> =
super.stringSetting(
title,
neededAtPhase,
init
) as ReadOnlyProperty<Any, PluginSetting<String, StringSettingType>>
@Suppress("UNCHECKED_CAST")
override fun <V : DisplayableSettingItem> dropDownSetting(
title: String,
neededAtPhase: GenerationPhase,
parser: Parser<V>,
prefix: String,
init: DropDownSettingType.Builder<V>.() -> Unit
): ReadOnlyProperty<Any, PluginSetting<V, DropDownSettingType<V>>> =
super.dropDownSetting(
title,
neededAtPhase,
parser,
prefix,
init
) as ReadOnlyProperty<Any, PluginSetting<V, DropDownSettingType<V>>>
@Suppress("UNCHECKED_CAST")
final override fun booleanSetting(
title: String,
neededAtPhase: GenerationPhase,
init: BooleanSettingType.Builder.() -> Unit
): ReadOnlyProperty<Any, PluginSetting<Boolean, BooleanSettingType>> =
super.booleanSetting(
title,
neededAtPhase,
init
) as ReadOnlyProperty<Any, PluginSetting<Boolean, BooleanSettingType>>
@Suppress("UNCHECKED_CAST")
override fun stringSetting(
title: String,
neededAtPhase: GenerationPhase,
prefix: String,
init: StringSettingType.Builder.() -> Unit
): ReadOnlyProperty<Any, PluginSetting<String, StringSettingType>> =
super.stringSetting(
title,
neededAtPhase,
prefix,
init
) as ReadOnlyProperty<Any, PluginSetting<String, StringSettingType>>
@Suppress("UNCHECKED_CAST")
final override fun <V : Any> valueSetting(
title: String,
neededAtPhase: GenerationPhase,
parser: Parser<V>,
init: ValueSettingType.Builder<V>.() -> Unit
): ReadOnlyProperty<Any, PluginSetting<V, ValueSettingType<V>>> =
super.valueSetting(
title,
neededAtPhase,
parser,
init
) as ReadOnlyProperty<Any, PluginSetting<V, ValueSettingType<V>>>
@Suppress("UNCHECKED_CAST")
override fun booleanSetting(
title: String,
neededAtPhase: GenerationPhase,
prefix: String,
init: BooleanSettingType.Builder.() -> Unit
): ReadOnlyProperty<Any, PluginSetting<Boolean, BooleanSettingType>> =
super.booleanSetting(
title,
neededAtPhase,
prefix,
init
) as ReadOnlyProperty<Any, PluginSetting<Boolean, BooleanSettingType>>
@Suppress("UNCHECKED_CAST")
final override fun versionSetting(
title: String,
neededAtPhase: GenerationPhase,
init: VersionSettingType.Builder.() -> Unit
): ReadOnlyProperty<Any, PluginSetting<Version, VersionSettingType>> =
super.versionSetting(
title,
neededAtPhase,
init
) as ReadOnlyProperty<Any, PluginSetting<Version, VersionSettingType>>
@Suppress("UNCHECKED_CAST")
override fun <V : Any> valueSetting(
title: String,
neededAtPhase: GenerationPhase,
parser: Parser<V>,
prefix: String,
init: ValueSettingType.Builder<V>.() -> Unit
): ReadOnlyProperty<Any, PluginSetting<V, ValueSettingType<V>>> =
super.valueSetting(
title,
neededAtPhase,
parser,
prefix,
init
) as ReadOnlyProperty<Any, PluginSetting<V, ValueSettingType<V>>>
@Suppress("UNCHECKED_CAST")
final override fun <V : Any> listSetting(
title: String,
neededAtPhase: GenerationPhase,
parser: Parser<V>,
init: ListSettingType.Builder<V>.() -> Unit
): ReadOnlyProperty<Any, PluginSetting<List<V>, ListSettingType<V>>> =
super.listSetting(
title,
neededAtPhase,
parser,
init
) as ReadOnlyProperty<Any, PluginSetting<List<V>, ListSettingType<V>>>
@Suppress("UNCHECKED_CAST")
override fun versionSetting(
title: String,
neededAtPhase: GenerationPhase,
prefix: String,
init: VersionSettingType.Builder.() -> Unit
): ReadOnlyProperty<Any, PluginSetting<Version, VersionSettingType>> =
super.versionSetting(
title,
neededAtPhase,
prefix,
init
) as ReadOnlyProperty<Any, PluginSetting<Version, VersionSettingType>>
@Suppress("UNCHECKED_CAST")
final override fun pathSetting(
title: String,
neededAtPhase: GenerationPhase,
init: PathSettingType.Builder.() -> Unit
): ReadOnlyProperty<Any, PluginSetting<Path, PathSettingType>> =
super.pathSetting(title, neededAtPhase, init) as ReadOnlyProperty<Any, PluginSetting<Path, PathSettingType>>
@Suppress("UNCHECKED_CAST")
override fun <V : Any> listSetting(
title: String,
neededAtPhase: GenerationPhase,
parser: Parser<V>,
prefix: String,
init: ListSettingType.Builder<V>.() -> Unit
): ReadOnlyProperty<Any, PluginSetting<List<V>, ListSettingType<V>>> =
super.listSetting(
title,
neededAtPhase,
parser,
prefix,
init
) as ReadOnlyProperty<Any, PluginSetting<List<V>, ListSettingType<V>>>
@Suppress("UNCHECKED_CAST")
inline fun <reified E> enumSetting(
title: String,
neededAtPhase: GenerationPhase,
crossinline init: DropDownSettingType.Builder<E>.() -> Unit = {}
): ReadOnlyProperty<Any, PluginSetting<E, DropDownSettingType<E>>> where E : Enum<E>, E : DisplayableSettingItem =
enumSettingImpl(title, neededAtPhase, init) as ReadOnlyProperty<Any, PluginSetting<E, DropDownSettingType<E>>>
@Suppress("UNCHECKED_CAST")
override fun pathSetting(
title: String,
neededAtPhase: GenerationPhase,
prefix: String,
init: PathSettingType.Builder.() -> Unit
): ReadOnlyProperty<Any, PluginSetting<Path, PathSettingType>> =
super.pathSetting(title, neededAtPhase, prefix, init) as ReadOnlyProperty<Any, PluginSetting<Path, PathSettingType>>
@Suppress("UNCHECKED_CAST")
inline fun <reified E> enumSetting(
title: String,
neededAtPhase: GenerationPhase,
prefix: String,
crossinline init: DropDownSettingType.Builder<E>.() -> Unit = {}
): ReadOnlyProperty<Any, PluginSetting<E, DropDownSettingType<E>>> where E : Enum<E>, E : DisplayableSettingItem =
enumSettingImpl(title, neededAtPhase, prefix, init) as ReadOnlyProperty<Any, PluginSetting<E, DropDownSettingType<E>>>
}
}
val PluginReference.withParentPlugins
get() = generateSequence(this) { klass ->
klass.supertypes.firstOrNull { supertype ->
supertype.classifier?.safeAs<KClass<Plugin>>()
?.isSubclassOf(Plugin::class) == true
}?.classifier
?.safeAs<KClass<Plugin>>()
?.takeIf { superClass ->
superClass.simpleName != null
}
}
val PluginReference.name
get() = simpleName
?.removeSuffix("Plugin")
?.decapitalize()
.orEmpty()
val PluginReference.path
get() = withParentPlugins.mapNotNull { klass ->
klass.name.takeIf { it.isNotEmpty() }
}.toList()
.reversed()
.joinToString(".")
@@ -1,12 +1,6 @@
package org.jetbrains.kotlin.tools.projectWizard.core.entity
import org.jetbrains.kotlin.tools.projectWizard.SettingsOwner
import org.jetbrains.kotlin.tools.projectWizard.core.PluginReference
import org.jetbrains.kotlin.tools.projectWizard.core.path
import org.jetbrains.kotlin.tools.projectWizard.core.safeAs
import kotlin.reflect.KProperty1
import kotlin.reflect.full.declaredMemberProperties
import kotlin.reflect.jvm.javaGetter
interface Entity {
val path: String
@@ -18,17 +12,3 @@ abstract class EntityBase: Entity {
}
abstract class EntityWithValue<out T : Any> : EntityBase()
typealias EntityReference = KProperty1<out SettingsOwner, Entity>
val EntityReference.path
get() = "${plugin.path}.$name"
@Suppress("UNCHECKED_CAST")
val <EP : EntityReference> EP.original
get() = plugin.declaredMemberProperties.first { it.name == name } as EP
@Suppress("UNCHECKED_CAST")
val EntityReference.plugin: PluginReference
get() = javaGetter!!.declaringClass.kotlin as PluginReference
@@ -1,47 +0,0 @@
package org.jetbrains.kotlin.tools.projectWizard.core.entity
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty
abstract class EntityContext<E : Entity, ER : EntityReference> {
private val entities = mutableMapOf<ER, E>()
open fun addEntity(entityReference: ER, createEntityByName: (String) -> E): E =
createEntityByName(entityReference.original.path).also {
entities[entityReference.original] = it
}
fun getEntity(entityReference: ER): E? = entities[entityReference.original]
fun getAll(): List<E> = entities.values.toList()
}
abstract class ValuedEntityContext<E : EntityWithValue<Any>, ER : EntityReference> : EntityContext<E, ER>() {
private val values = mutableMapOf<String, Any>()
operator fun get(entityReference: ER) =
values[entityReference.original.path]
operator fun get(entityPath: String) =
values[entityPath]
open operator fun set(entityReference: ER, value: Any) {
values[entityReference.original.path] = value
}
open operator fun set(entityPath: String, value: Any) {
values[entityPath] = value
}
val allValues: Map<String, Any> = values
}
@Suppress("UNCHECKED_CAST")
fun <E : Entity, A : E, ER : EntityReference> entityDelegate(
entityContext: EntityContext<E, ER>,
createEntityByPath: (String) -> A
) = object : ReadOnlyProperty<Any, A> {
override fun getValue(thisRef: Any, property: KProperty<*>): A =
entityContext.getEntity(property as ER) as? A
?: entityContext.addEntity(property, createEntityByPath) as A
}
@@ -1,12 +1,6 @@
package org.jetbrains.kotlin.tools.projectWizard.core.entity
import org.jetbrains.kotlin.tools.projectWizard.core.Plugin
import kotlin.reflect.KProperty1
typealias PropertyReference<T> = KProperty1<out Plugin, Property<T>>
class PropertyContext : ValuedEntityContext<Property<Any>, PropertyReference<Any>>()
class PropertyContext : ValuedEntityContext<Property<Any>>()
data class Property<out T : Any>(
override val path: String,
@@ -6,12 +6,6 @@ import org.jetbrains.kotlin.tools.projectWizard.core.*
import org.jetbrains.kotlin.tools.projectWizard.phases.GenerationPhase
import kotlin.reflect.KProperty1
typealias TaskReference = KProperty1<out Plugin, Task>
typealias Task1Reference<A, B> = KProperty1<out Plugin, Task1<A, B>>
typealias PipelineTaskReference = KProperty1<out Plugin, PipelineTask>
class TaskContext : EntityContext<Task, TaskReference>()
sealed class Task : EntityBase()
data class Task1<A, B : Any>(
@@ -32,8 +26,8 @@ data class Task1<A, B : Any>(
data class PipelineTask(
override val path: String,
val action: Writer.() -> TaskResult<Unit>,
val before: List<PipelineTaskReference>,
val after: List<PipelineTaskReference>,
val before: List<PipelineTask>,
val after: List<PipelineTask>,
val phase: GenerationPhase,
val isAvailable: Checker,
val title: String?
@@ -43,8 +37,8 @@ data class PipelineTask(
private val phase: GenerationPhase
) {
private var action: Writer.() -> TaskResult<Unit> = { UNIT_SUCCESS }
private val before = mutableListOf<PipelineTaskReference>()
private val after = mutableListOf<PipelineTaskReference>()
private val before = mutableListOf<PipelineTask>()
private val after = mutableListOf<PipelineTask>()
var isAvailable: Checker = ALWAYS_AVAILABLE_CHECKER
@@ -55,11 +49,11 @@ data class PipelineTask(
this.action = action
}
fun runBefore(vararg before: PipelineTaskReference) {
fun runBefore(vararg before: PipelineTask) {
this.before.addAll(before)
}
fun runAfter(vararg after: PipelineTaskReference) {
fun runAfter(vararg after: PipelineTask) {
this.after.addAll(after)
}
@@ -0,0 +1,15 @@
package org.jetbrains.kotlin.tools.projectWizard.core.entity
abstract class ValuedEntityContext<E : EntityWithValue<Any>> {
private val values = mutableMapOf<String, Any>()
@Suppress("UNCHECKED_CAST")
operator fun <V : Any> get(entity: E) =
values[entity.path] as? V
open operator fun set(entity: E, value: Any) {
values[entity.path] = value
}
}
@@ -6,9 +6,6 @@
package org.jetbrains.kotlin.tools.projectWizard.core.entity.settings
import org.jetbrains.kotlin.tools.projectWizard.core.EventManager
import org.jetbrains.kotlin.tools.projectWizard.core.entity.path
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty
class SettingContext {
private val values = mutableMapOf<String, Any>()
@@ -32,27 +29,10 @@ class SettingContext {
fun <V : Any, T : SettingType<V>> getPluginSetting(pluginSettingReference: PluginSettingReference<V, T>) =
pluginSettings[pluginSettingReference.path] as PluginSetting<V, T>
@Suppress("UNCHECKED_CAST")
private fun <V : Any, T : SettingType<V>> getPluginSetting(pluginSettingReference: PluginSettingPropertyReference<V, T>) =
pluginSettings[pluginSettingReference.path] as? PluginSetting<V, T>
private fun <V : Any, T : SettingType<V>> setPluginSetting(
pluginSettingReference: PluginSettingPropertyReference<V, T>,
fun <V : Any, T : SettingType<V>> setPluginSetting(
pluginSettingReference: PluginSettingReference<V, T>,
setting: PluginSetting<V, T>
) {
pluginSettings[pluginSettingReference.path] = setting
}
fun <V : Any, T : SettingType<V>> settingDelegate(
create: (path: String) -> SettingBuilder<V, T>
): ReadOnlyProperty<Any, PluginSetting<V, T>> = object : ReadOnlyProperty<Any, PluginSetting<V, T>> {
override fun getValue(thisRef: Any, property: KProperty<*>): PluginSetting<V, T> {
@Suppress("UNCHECKED_CAST")
val reference = property as PluginSettingPropertyReference<V, T>
getPluginSetting(reference)?.let { return it }
val setting = PluginSetting(create(reference.path).buildInternal())
setPluginSetting(reference, setting)
return setting
}
}
}
@@ -7,15 +7,12 @@ package org.jetbrains.kotlin.tools.projectWizard.core.entity.settings
import org.jetbrains.annotations.NonNls
import org.jetbrains.kotlin.tools.projectWizard.Identificator
import org.jetbrains.kotlin.tools.projectWizard.core.Plugin
import org.jetbrains.kotlin.tools.projectWizard.core.Reader
import org.jetbrains.kotlin.tools.projectWizard.core.entity.path
import org.jetbrains.kotlin.tools.projectWizard.core.safeAs
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.ModuleConfigurator
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.Module
import org.jetbrains.kotlin.tools.projectWizard.templates.Template
import kotlin.reflect.KClass
import kotlin.reflect.KProperty1
sealed class SettingReference<out V : Any, out T : SettingType<V>> {
@@ -35,9 +32,6 @@ data class PluginSettingReference<out V : Any, out T : SettingType<V>>(
override val type: KClass<@UnsafeVariance T>
) : SettingReference<V, T>() {
constructor(kProperty: KProperty1<out Plugin, PluginSetting<V, T>>, type: KClass<T>) :
this(kProperty.path, type)
@Suppress("UNCHECKED_CAST")
constructor(setting: PluginSetting<V, T>) :
this(setting.path, setting.type::class as KClass<T>)
@@ -112,8 +106,8 @@ data class IdBasedTemplateSettingReference<V : Any, T : SettingType<V>>(
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>
get() = PluginSettingReference(this, T::class)
typealias PluginSettingPropertyReference<V, T> = KProperty1<out Plugin, PluginSetting<V, T>>
typealias PluginSettingPropertyReference<V, T> = KProperty1<out Plugin, PluginSetting<V, T>>*/
@@ -3,7 +3,6 @@ package org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.plus
import kotlinx.collections.immutable.toPersistentList
import kotlin.reflect.full.isSubclassOf
interface IrsOwner {
@@ -20,7 +19,7 @@ fun <I : IrsOwner> I.withIrs(vararg irs: BuildSystemIR) = withReplacedIrs(irs =
inline fun <reified I : BuildSystemIR> IrsOwner.irsOfType(): List<I> =
irs.filterIsInstance<I>().let { irs ->
if (I::class.isSubclassOf(BuildSystemIRWithPriority::class))
if (irs.all { it is BuildSystemIRWithPriority })
irs.sortedBy { (it as BuildSystemIRWithPriority).priority }
else irs
}
@@ -44,7 +44,7 @@ interface AndroidModuleConfigurator : ModuleConfigurator,
get() = ModuleType.android
override fun getPluginSettings(): List<PluginSettingReference<Any, SettingType<Any>>> =
listOf(AndroidPlugin::androidSdkPath.reference)
listOf(AndroidPlugin.androidSdkPath.reference)
override fun createBuildFileIRs(
reader: Reader,
@@ -66,7 +66,7 @@ interface AndroidModuleConfigurator : ModuleConfigurator,
fun Reader.createAndroidPlugin(module: Module): AndroidGradlePlugin
override fun Reader.createSettingsGradleIRs(module: Module) = buildList<BuildSystemIR> {
+createRepositories(KotlinPlugin::version.propertyValue).map { PluginManagementRepositoryIR(RepositoryIR(it)) }
+createRepositories(KotlinPlugin.version.propertyValue).map { PluginManagementRepositoryIR(RepositoryIR(it)) }
+AndroidResolutionStrategyIR(Versions.GRADLE_PLUGINS.ANDROID)
}
@@ -154,7 +154,7 @@ object AndroidTargetConfigurator : TargetConfigurator,
): TaskResult<Unit> = computeM {
val javaPackage = module.javaPackage(configurationData.pomIr)
val settings = mapOf("package" to javaPackage.asCodePackage())
TemplatesPlugin::addFileTemplates.execute(
TemplatesPlugin.addFileTemplates.execute(
listOf(
FileTemplate(AndroidModuleConfigurator.FileTemplateDescriptors.androidManifestForLibraryXml, modulePath, settings)
)
@@ -96,7 +96,7 @@ object AndroidSinglePlatformModuleConfigurator :
): TaskResult<Unit> = computeM {
val javaPackage = module.javaPackage(configurationData.pomIr)
val settings = mapOf("package" to javaPackage.asCodePackage())
TemplatesPlugin::addFileTemplates.execute(
TemplatesPlugin.addFileTemplates.execute(
listOf(
FileTemplate(AndroidModuleConfigurator.FileTemplateDescriptors.activityMainXml, modulePath, settings),
FileTemplate(AndroidModuleConfigurator.FileTemplateDescriptors.androidManifestXml, modulePath, settings),
@@ -36,7 +36,7 @@ object IOSSinglePlatformModuleConfigurator : SinglePlatformModuleConfigurator, M
module: Module,
modulePath: Path
): TaskResult<Unit> =
GradlePlugin::gradleProperties.addValues("xcodeproj" to "./${module.name}")
GradlePlugin.gradleProperties.addValues("xcodeproj" to "./${module.name}")
override fun Reader.createTemplates(
configurationData: ModulesToIrConversionData,
@@ -62,6 +62,7 @@ fun <V : Any, T : SettingType<V>> Reader.settingValue(module: Module, setting: M
abstract class ModuleConfiguratorSettings : SettingsOwner {
final override fun <V : Any, T : SettingType<V>> settingDelegate(
prefix: String,
create: (path: String) -> SettingBuilder<V, T>
): ReadOnlyProperty<Any?, ModuleConfiguratorSetting<V, T>> = cached { name ->
ModuleConfiguratorSetting(create(name).buildInternal())
@@ -72,12 +73,14 @@ abstract class ModuleConfiguratorSettings : SettingsOwner {
title: String,
neededAtPhase: GenerationPhase,
parser: Parser<V>,
prefix: String,
init: DropDownSettingType.Builder<V>.() -> Unit
): ReadOnlyProperty<Any, ModuleConfiguratorSetting<V, DropDownSettingType<V>>> =
super.dropDownSetting(
title,
neededAtPhase,
parser,
prefix,
init
) as ReadOnlyProperty<Any, ModuleConfiguratorSetting<V, DropDownSettingType<V>>>
@@ -85,11 +88,13 @@ abstract class ModuleConfiguratorSettings : SettingsOwner {
final override fun stringSetting(
title: String,
neededAtPhase: GenerationPhase,
prefix: String,
init: StringSettingType.Builder.() -> Unit
): ReadOnlyProperty<Any, ModuleConfiguratorSetting<String, StringSettingType>> =
super.stringSetting(
title,
neededAtPhase,
prefix,
init
) as ReadOnlyProperty<Any, ModuleConfiguratorSetting<String, StringSettingType>>
@@ -97,11 +102,13 @@ abstract class ModuleConfiguratorSettings : SettingsOwner {
final override fun booleanSetting(
title: String,
neededAtPhase: GenerationPhase,
prefix: String,
init: BooleanSettingType.Builder.() -> Unit
): ReadOnlyProperty<Any, ModuleConfiguratorSetting<Boolean, BooleanSettingType>> =
super.booleanSetting(
title,
neededAtPhase,
prefix,
init
) as ReadOnlyProperty<Any, ModuleConfiguratorSetting<Boolean, BooleanSettingType>>
@@ -110,12 +117,14 @@ abstract class ModuleConfiguratorSettings : SettingsOwner {
title: String,
neededAtPhase: GenerationPhase,
parser: Parser<V>,
prefix: String,
init: ValueSettingType.Builder<V>.() -> Unit
): ReadOnlyProperty<Any, ModuleConfiguratorSetting<V, ValueSettingType<V>>> =
super.valueSetting(
title,
neededAtPhase,
parser,
prefix,
init
) as ReadOnlyProperty<Any, ModuleConfiguratorSetting<V, ValueSettingType<V>>>
@@ -123,11 +132,13 @@ abstract class ModuleConfiguratorSettings : SettingsOwner {
final override fun versionSetting(
title: String,
neededAtPhase: GenerationPhase,
prefix: String,
init: VersionSettingType.Builder.() -> Unit
): ReadOnlyProperty<Any, ModuleConfiguratorSetting<Version, VersionSettingType>> =
super.versionSetting(
title,
neededAtPhase,
prefix,
init
) as ReadOnlyProperty<Any, ModuleConfiguratorSetting<Version, VersionSettingType>>
@@ -136,12 +147,14 @@ abstract class ModuleConfiguratorSettings : SettingsOwner {
title: String,
neededAtPhase: GenerationPhase,
parser: Parser<V>,
prefix: String,
init: ListSettingType.Builder<V>.() -> Unit
): ReadOnlyProperty<Any, ModuleConfiguratorSetting<List<V>, ListSettingType<V>>> =
super.listSetting(
title,
neededAtPhase,
parser,
prefix,
init
) as ReadOnlyProperty<Any, ModuleConfiguratorSetting<List<V>, ListSettingType<V>>>
@@ -149,11 +162,13 @@ abstract class ModuleConfiguratorSettings : SettingsOwner {
final override fun pathSetting(
title: String,
neededAtPhase: GenerationPhase,
prefix: String,
init: PathSettingType.Builder.() -> Unit
): ReadOnlyProperty<Any, ModuleConfiguratorSetting<Path, PathSettingType>> =
super.pathSetting(
title,
neededAtPhase,
prefix,
init
) as ReadOnlyProperty<Any, ModuleConfiguratorSetting<Path, PathSettingType>>
@@ -161,9 +176,10 @@ abstract class ModuleConfiguratorSettings : SettingsOwner {
inline fun <reified E> enumSetting(
title: String,
neededAtPhase: GenerationPhase,
prefix: String = "",
crossinline init: DropDownSettingType.Builder<E>.() -> Unit = {}
): ReadOnlyProperty<Any, ModuleConfiguratorSetting<E, DropDownSettingType<E>>> where E : Enum<E>, E : DisplayableSettingItem =
enumSettingImpl(title, neededAtPhase, init) as ReadOnlyProperty<Any, ModuleConfiguratorSetting<E, DropDownSettingType<E>>>
enumSettingImpl(title, neededAtPhase, prefix, init) as ReadOnlyProperty<Any, ModuleConfiguratorSetting<E, DropDownSettingType<E>>>
}
interface ModuleConfiguratorWithSettings : ModuleConfigurator {
@@ -63,7 +63,7 @@ interface ModuleConfiguratorWithTests : ModuleConfiguratorWithSettings {
dependencyName,
isInMppModule = module.kind
.let { it == ModuleKind.multiplatform || it == ModuleKind.target },
kotlinVersion = KotlinPlugin::version.propertyValue,
kotlinVersion = KotlinPlugin.version.propertyValue,
dependencyType = DependencyType.TEST
)
}
@@ -1,6 +1,7 @@
package org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators
import kotlinx.collections.immutable.toPersistentList
import org.jetbrains.annotations.NonNls
import org.jetbrains.kotlin.tools.projectWizard.KotlinNewProjectWizardBundle
import org.jetbrains.kotlin.tools.projectWizard.core.Reader
@@ -10,10 +11,15 @@ import org.jetbrains.kotlin.tools.projectWizard.core.safeAs
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.BuildSystemIR
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.KotlinBuildSystemPluginIR
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle.*
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle.multiplatform.DefaultTargetConfigurationIR
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle.multiplatform.TargetAccessIR
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.maven.MavenPropertyIR
import org.jetbrains.kotlin.tools.projectWizard.phases.GenerationPhase
import org.jetbrains.kotlin.tools.projectWizard.plugins.buildSystem.BuildSystemType
import org.jetbrains.kotlin.tools.projectWizard.plugins.buildSystem.gradle.GradlePlugin
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.ModuleType
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ModulesToIrConversionData
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ModuleType
import org.jetbrains.kotlin.tools.projectWizard.settings.DisplayableSettingItem
@@ -11,9 +11,8 @@ import org.jetbrains.kotlin.tools.projectWizard.core.Plugin
import org.jetbrains.kotlin.tools.projectWizard.core.UNIT_SUCCESS
import org.jetbrains.kotlin.tools.projectWizard.core.checker
import org.jetbrains.kotlin.tools.projectWizard.core.entity.PipelineTask
import org.jetbrains.kotlin.tools.projectWizard.core.entity.Task
import org.jetbrains.kotlin.tools.projectWizard.core.entity.Property
import org.jetbrains.kotlin.tools.projectWizard.core.entity.settings.PluginSetting
import org.jetbrains.kotlin.tools.projectWizard.core.service.FileSystemWizardService
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.AndroidModuleConfigurator
import org.jetbrains.kotlin.tools.projectWizard.phases.GenerationPhase
import org.jetbrains.kotlin.tools.projectWizard.plugins.buildSystem.allIRModules
@@ -22,36 +21,7 @@ import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.KotlinPlugin
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.withAllSubModules
class AndroidPlugin(context: Context) : Plugin(context) {
override val path = "android"
val androidSdkPath by pathSetting(
KotlinNewProjectWizardBundle.message("plugin.android.setting.sdk"),
neededAtPhase = GenerationPhase.PROJECT_GENERATION
) {
isSavable = true
isAvailable = isAndroidContainingProject
shouldExists()
}
private val isAndroidContainingProject = checker {
KotlinPlugin::modules.settingValue
.withAllSubModules(includeSourcesets = true)
.any { it.configurator is AndroidModuleConfigurator }
}
val addAndroidSdkToLocalProperties by pipelineTask(GenerationPhase.PROJECT_GENERATION) {
runBefore(GradlePlugin::createLocalPropertiesFile)
runAfter(KotlinPlugin::createModules)
isAvailable = isAndroidContainingProject
withAction {
if (allIRModules.none { it.originalModule.configurator is AndroidModuleConfigurator }) return@withAction UNIT_SUCCESS
val path = AndroidPlugin::androidSdkPath.settingValue
val fileSystemService = service<FileSystemWizardService>()
GradlePlugin::localProperties.addValues(
"sdk.dir" to fileSystemService.renderPath(path)
)
}
}
override val path = PATH
override val settings: List<PluginSetting<*, *>> = listOf(
androidSdkPath
@@ -59,4 +29,40 @@ class AndroidPlugin(context: Context) : Plugin(context) {
override val pipelineTasks: List<PipelineTask> = listOf(
addAndroidSdkToLocalProperties
)
override val properties: List<Property<*>> = listOf()
companion object {
private const val PATH = "android"
val androidSdkPath by pathSetting(
KotlinNewProjectWizardBundle.message("plugin.android.setting.sdk"),
neededAtPhase = GenerationPhase.PROJECT_GENERATION,
PATH
) {
isSavable = true
isAvailable = isAndroidContainingProject
shouldExists()
}
private val isAndroidContainingProject = checker {
KotlinPlugin.modules.settingValue
.withAllSubModules(includeSourcesets = true)
.any { it.configurator is AndroidModuleConfigurator }
}
val addAndroidSdkToLocalProperties by pipelineTask(PATH, GenerationPhase.PROJECT_GENERATION) {
runBefore(GradlePlugin.createLocalPropertiesFile)
runAfter(KotlinPlugin.createModules)
isAvailable = isAndroidContainingProject
withAction {
if (allIRModules.none { it.originalModule.configurator is AndroidModuleConfigurator }) return@withAction UNIT_SUCCESS
val path = androidSdkPath.settingValue
val fileSystemService = service<FileSystemWizardService>()
GradlePlugin.localProperties.addValues(
"sdk.dir" to fileSystemService.renderPath(path)
)
}
}
}
}
@@ -10,27 +10,33 @@ import org.jetbrains.kotlin.tools.projectWizard.core.Context
import org.jetbrains.kotlin.tools.projectWizard.core.Plugin
import org.jetbrains.kotlin.tools.projectWizard.core.UNIT_SUCCESS
import org.jetbrains.kotlin.tools.projectWizard.core.entity.PipelineTask
import org.jetbrains.kotlin.tools.projectWizard.core.entity.Property
import org.jetbrains.kotlin.tools.projectWizard.core.entity.settings.PluginSetting
import org.jetbrains.kotlin.tools.projectWizard.core.service.RunConfigurationsService
import org.jetbrains.kotlin.tools.projectWizard.phases.GenerationPhase
import org.jetbrains.kotlin.tools.projectWizard.plugins.buildSystem.BuildSystemPlugin
class RunConfigurationsPlugin(context: Context) : Plugin(context) {
override val path = "runConfigurations"
val configurations by listProperty<WizardRunConfiguration>()
val createRunConfigurationsTask by pipelineTask(GenerationPhase.PROJECT_IMPORT) {
runBefore(BuildSystemPlugin::importProject)
withAction {
service<RunConfigurationsService>().apply {
addRunConfigurations(RunConfigurationsPlugin::configurations.propertyValue)
}
UNIT_SUCCESS
}
}
override val path = PATH
override val settings: List<PluginSetting<*, *>> = emptyList()
override val pipelineTasks: List<PipelineTask> = listOf(createRunConfigurationsTask)
override val properties: List<Property<*>> = listOf(configurations)
companion object {
private const val PATH = "runConfigurations"
val configurations by listProperty<WizardRunConfiguration>(PATH)
val createRunConfigurationsTask by pipelineTask(PATH, GenerationPhase.PROJECT_IMPORT) {
runBefore(BuildSystemPlugin.importProject)
withAction {
service<RunConfigurationsService>().apply {
addRunConfigurations(configurations.propertyValue)
}
UNIT_SUCCESS
}
}
}
}
@@ -4,6 +4,7 @@ package org.jetbrains.kotlin.tools.projectWizard.plugins
import org.jetbrains.kotlin.tools.projectWizard.KotlinNewProjectWizardBundle
import org.jetbrains.kotlin.tools.projectWizard.core.*
import org.jetbrains.kotlin.tools.projectWizard.core.entity.PipelineTask
import org.jetbrains.kotlin.tools.projectWizard.core.entity.Property
import org.jetbrains.kotlin.tools.projectWizard.core.entity.StringValidators
import org.jetbrains.kotlin.tools.projectWizard.core.entity.ValidationResult
import org.jetbrains.kotlin.tools.projectWizard.core.entity.settings.PluginSetting
@@ -17,58 +18,70 @@ import java.nio.file.Files
import java.nio.file.Paths
class StructurePlugin(context: Context) : Plugin(context) {
override val path = "structure"
override val path = PATH
val projectPath by pathSetting(
KotlinNewProjectWizardBundle.message("plugin.structure.setting.location"),
GenerationPhase.FIRST_STEP
) {
defaultValue = value(Paths.get("."))
companion object {
private const val PATH = "structure"
validateOnProjectCreation = false
private val ALLOWED_SPECIAL_CHARS_IN_GROUP_ID = Module.ALLOWED_SPECIAL_CHARS_IN_MODULE_NAMES + '.'
private val ALLOWED_SPECIAL_CHARS_IN_ARTIFACT_ID = Module.ALLOWED_SPECIAL_CHARS_IN_MODULE_NAMES
private val ALLOWED_SPECIAL_CHARS_IN_VERSION = setOf('_', '-', '.')
validate { path ->
if (!Files.exists(path)) return@validate ValidationResult.OK
ValidationResult.create(Files.list(path).noneMatch { true }) {
KotlinNewProjectWizardBundle.message("plugin.structure.setting.location.error.is.not.empty")
val projectPath by pathSetting(
KotlinNewProjectWizardBundle.message("plugin.structure.setting.location"),
GenerationPhase.FIRST_STEP,
PATH
) {
defaultValue = value(Paths.get("."))
validateOnProjectCreation = false
validate { path ->
if (!Files.exists(path)) return@validate ValidationResult.OK
ValidationResult.create(Files.list(path).noneMatch { true }) {
KotlinNewProjectWizardBundle.message("plugin.structure.setting.location.error.is.not.empty")
}
}
}
}
val name by stringSetting(
KotlinNewProjectWizardBundle.message("plugin.structure.setting.name"),
GenerationPhase.FIRST_STEP
) {
shouldNotBeBlank()
validate(StringValidators.shouldBeValidIdentifier(title, Module.ALLOWED_SPECIAL_CHARS_IN_MODULE_NAMES))
}
val name by stringSetting(
KotlinNewProjectWizardBundle.message("plugin.structure.setting.name"),
GenerationPhase.FIRST_STEP,
PATH
) {
shouldNotBeBlank()
validate(StringValidators.shouldBeValidIdentifier(title, Module.ALLOWED_SPECIAL_CHARS_IN_MODULE_NAMES))
}
val groupId by stringSetting(
KotlinNewProjectWizardBundle.message("plugin.structure.setting.group.id"),
GenerationPhase.FIRST_STEP
) {
isSavable = true
shouldNotBeBlank()
validate(StringValidators.shouldBeValidIdentifier(title, ALLOWED_SPECIAL_CHARS_IN_GROUP_ID))
}
val artifactId by stringSetting(
KotlinNewProjectWizardBundle.message("plugin.structure.setting.artifact.id"),
GenerationPhase.FIRST_STEP
) {
shouldNotBeBlank()
validate(StringValidators.shouldBeValidIdentifier(title, ALLOWED_SPECIAL_CHARS_IN_ARTIFACT_ID))
}
val version by stringSetting(
KotlinNewProjectWizardBundle.message("plugin.structure.setting.version"),
GenerationPhase.FIRST_STEP
) {
shouldNotBeBlank()
validate(StringValidators.shouldBeValidIdentifier(title, ALLOWED_SPECIAL_CHARS_IN_VERSION))
defaultValue = value("1.0-SNAPSHOT")
}
val createProjectDir by pipelineTask(GenerationPhase.PROJECT_GENERATION) {
withAction {
service<FileSystemWizardService>().createDirectory(StructurePlugin::projectPath.reference.settingValue)
val groupId by stringSetting(
KotlinNewProjectWizardBundle.message("plugin.structure.setting.group.id"),
GenerationPhase.FIRST_STEP,
PATH
) {
isSavable = true
shouldNotBeBlank()
validate(StringValidators.shouldBeValidIdentifier(title, ALLOWED_SPECIAL_CHARS_IN_GROUP_ID))
}
val artifactId by stringSetting(
KotlinNewProjectWizardBundle.message("plugin.structure.setting.artifact.id"),
GenerationPhase.FIRST_STEP,
PATH
) {
shouldNotBeBlank()
validate(StringValidators.shouldBeValidIdentifier(title, ALLOWED_SPECIAL_CHARS_IN_ARTIFACT_ID))
}
val version by stringSetting(
KotlinNewProjectWizardBundle.message("plugin.structure.setting.version"),
GenerationPhase.FIRST_STEP,
PATH
) {
shouldNotBeBlank()
validate(StringValidators.shouldBeValidIdentifier(title, ALLOWED_SPECIAL_CHARS_IN_VERSION))
defaultValue = value("1.0-SNAPSHOT")
}
val createProjectDir by pipelineTask(PATH, GenerationPhase.PROJECT_GENERATION) {
withAction {
service<FileSystemWizardService>().createDirectory(StructurePlugin.projectPath.settingValue)
}
}
}
@@ -82,23 +95,18 @@ class StructurePlugin(context: Context) : Plugin(context) {
)
override val pipelineTasks: List<PipelineTask> =
listOf(createProjectDir)
companion object {
private val ALLOWED_SPECIAL_CHARS_IN_GROUP_ID = Module.ALLOWED_SPECIAL_CHARS_IN_MODULE_NAMES + '.'
private val ALLOWED_SPECIAL_CHARS_IN_ARTIFACT_ID = Module.ALLOWED_SPECIAL_CHARS_IN_MODULE_NAMES
private val ALLOWED_SPECIAL_CHARS_IN_VERSION = setOf('_', '-', '.')
}
override val properties: List<Property<*>> = listOf()
}
val Reader.projectPath
get() = StructurePlugin::projectPath.reference.settingValue
get() = StructurePlugin.projectPath.settingValue
val Reader.projectName
get() = StructurePlugin::name.reference.settingValue
get() = StructurePlugin.name.settingValue
fun Writer.pomIR() = PomIR(
artifactId = StructurePlugin::artifactId.reference.settingValue,
groupId = StructurePlugin::groupId.reference.settingValue,
version = Version.fromString(StructurePlugin::version.reference.settingValue)
artifactId = StructurePlugin.artifactId.settingValue,
groupId = StructurePlugin.groupId.settingValue,
version = Version.fromString(StructurePlugin.version.settingValue)
)
@@ -6,9 +6,9 @@ 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.PipelineTask
import org.jetbrains.kotlin.tools.projectWizard.core.entity.Property
import org.jetbrains.kotlin.tools.projectWizard.core.entity.ValidationResult
import org.jetbrains.kotlin.tools.projectWizard.core.entity.settings.PluginSetting
import org.jetbrains.kotlin.tools.projectWizard.core.entity.settings.reference
import org.jetbrains.kotlin.tools.projectWizard.core.service.BuildSystemAvailabilityWizardService
import org.jetbrains.kotlin.tools.projectWizard.core.service.FileSystemWizardService
import org.jetbrains.kotlin.tools.projectWizard.core.service.ProjectImportingWizardService
@@ -27,91 +27,96 @@ import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.Repository
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.updateBuildFiles
abstract class BuildSystemPlugin(context: Context) : Plugin(context) {
override val path = "buildSystem"
override val path = PATH
val type by enumSetting<BuildSystemType>(
KotlinNewProjectWizardBundle.message("plugin.buildsystem.setting.type"),
GenerationPhase.FIRST_STEP
) {
isSavable = true
filter = { _, type ->
val service = service<BuildSystemAvailabilityWizardService>()
service.isAvailable(type)
}
companion object {
private const val PATH = "buildSystem"
validate { buildSystemType ->
if (!buildSystemType.isGradle
&& KotlinPlugin::projectKind.reference.notRequiredSettingValue != ProjectKind.Singleplatform
) {
val projectKind = KotlinPlugin::projectKind.reference.notRequiredSettingValue?.text?.capitalize()
?: KotlinNewProjectWizardBundle.message("project")
ValidationResult.ValidationError(
KotlinNewProjectWizardBundle.message(
"plugin.buildsystem.setting.type.error.wrong.project.kind",
projectKind,
buildSystemType.fullText
val type by enumSetting<BuildSystemType>(
KotlinNewProjectWizardBundle.message("plugin.buildsystem.setting.type"),
GenerationPhase.FIRST_STEP,
PATH
) {
isSavable = true
filter = { _, type ->
val service = service<BuildSystemAvailabilityWizardService>()
service.isAvailable(type)
}
validate { buildSystemType ->
if (!buildSystemType.isGradle
&& KotlinPlugin.projectKind.notRequiredSettingValue != ProjectKind.Singleplatform
) {
val projectKind = KotlinPlugin.projectKind.notRequiredSettingValue?.text?.capitalize()
?: KotlinNewProjectWizardBundle.message("project")
ValidationResult.ValidationError(
KotlinNewProjectWizardBundle.message(
"plugin.buildsystem.setting.type.error.wrong.project.kind",
projectKind,
buildSystemType.fullText
)
)
)
} else ValidationResult.OK
} else ValidationResult.OK
}
}
}
val buildSystemData by property<List<BuildSystemData>>(emptyList())
val buildSystemData by property<List<BuildSystemData>>(PATH, emptyList())
val buildFiles by listProperty<BuildFileIR>()
val buildFiles by listProperty<BuildFileIR>(PATH)
val pluginRepositoreis by listProperty<Repository>()
val pluginRepositoreis by listProperty<Repository>(PATH)
val takeRepositoriesFromDependencies by pipelineTask(GenerationPhase.PROJECT_GENERATION) {
runBefore(BuildSystemPlugin::createModules)
runAfter(TemplatesPlugin::postApplyTemplatesToModules)
val takeRepositoriesFromDependencies by pipelineTask(PATH, GenerationPhase.PROJECT_GENERATION) {
runBefore(createModules)
runAfter(TemplatesPlugin.postApplyTemplatesToModules)
withAction {
updateBuildFiles { buildFile ->
val dependenciesOfModule = buildList<LibraryDependencyIR> {
buildFile.modules.modules.forEach { module ->
if (module is SingleplatformModuleIR) module.sourcesets.forEach { sourceset ->
+sourceset.irs.filterIsInstance<LibraryDependencyIR>()
withAction {
updateBuildFiles { buildFile ->
val dependenciesOfModule = buildList<LibraryDependencyIR> {
buildFile.modules.modules.forEach { module ->
if (module is SingleplatformModuleIR) module.sourcesets.forEach { sourceset ->
+sourceset.irs.filterIsInstance<LibraryDependencyIR>()
}
+module.irs.filterIsInstance<LibraryDependencyIR>()
}
+module.irs.filterIsInstance<LibraryDependencyIR>()
}
val repositoriesToAdd = dependenciesOfModule.mapNotNull { dependency ->
dependency.artifact.safeAs<MavenArtifact>()?.repository?.let(::RepositoryIR)
}
buildFile.withIrs(repositoriesToAdd).asSuccess()
}
val repositoriesToAdd = dependenciesOfModule.mapNotNull { dependency ->
dependency.artifact.safeAs<MavenArtifact>()?.repository?.let(::RepositoryIR)
}
buildFile.withIrs(repositoriesToAdd).asSuccess()
}
}
}
val createModules by pipelineTask(GenerationPhase.PROJECT_GENERATION) {
runAfter(StructurePlugin::createProjectDir)
withAction {
val fileSystem = service<FileSystemWizardService>()
val data = BuildSystemPlugin::buildSystemData.propertyValue.first { it.type == buildSystemType }
val buildFileData = data.buildFileData ?: return@withAction UNIT_SUCCESS
BuildSystemPlugin::buildFiles.propertyValue.mapSequenceIgnore { buildFile ->
fileSystem.createFile(
buildFile.directoryPath / buildFileData.buildFileName,
buildFileData.createPrinter().printBuildFile { buildFile.render(this) }
)
val createModules by pipelineTask(PATH, GenerationPhase.PROJECT_GENERATION) {
runAfter(StructurePlugin.createProjectDir)
withAction {
val fileSystem = service<FileSystemWizardService>()
val data = buildSystemData.propertyValue.first { it.type == buildSystemType }
val buildFileData = data.buildFileData ?: return@withAction UNIT_SUCCESS
buildFiles.propertyValue.mapSequenceIgnore { buildFile ->
fileSystem.createFile(
buildFile.directoryPath / buildFileData.buildFileName,
buildFileData.createPrinter().printBuildFile { buildFile.render(this) }
)
}
}
}
}
val importProject by pipelineTask(GenerationPhase.PROJECT_IMPORT) {
runAfter(BuildSystemPlugin::createModules)
withAction {
val data = BuildSystemPlugin::buildSystemData.propertyValue.first { it.type == buildSystemType }
service<ProjectImportingWizardService> { service -> service.isSuitableFor(data.type) }
.importProject(this, StructurePlugin::projectPath.reference.settingValue, allIRModules, buildSystemType)
val importProject by pipelineTask(PATH, GenerationPhase.PROJECT_IMPORT) {
runAfter(createModules)
withAction {
val data = buildSystemData.propertyValue.first { it.type == buildSystemType }
service<ProjectImportingWizardService> { service -> service.isSuitableFor(data.type) }
.importProject(this, StructurePlugin.projectPath.settingValue, allIRModules, buildSystemType)
}
}
}
protected fun addBuildSystemData(data: BuildSystemData) = pipelineTask(GenerationPhase.PREPARE) {
runBefore(BuildSystemPlugin::createModules)
withAction {
BuildSystemPlugin::buildSystemData.addValues(data)
fun addBuildSystemData(prefix: String, data: BuildSystemData) = pipelineTask(prefix, GenerationPhase.PREPARE) {
runBefore(createModules)
withAction {
buildSystemData.addValues(data)
}
}
}
@@ -123,6 +128,11 @@ abstract class BuildSystemPlugin(context: Context) : Plugin(context) {
createModules,
importProject,
)
override val properties: List<Property<*>> = listOf(
buildSystemData,
buildFiles,
pluginRepositoreis
)
}
data class BuildSystemData(
@@ -169,12 +179,12 @@ val BuildSystemType.isGradle
|| this == BuildSystemType.GradleKotlinDsl
val Reader.allIRModules
get() = BuildSystemPlugin::buildFiles.propertyValue.flatMap { buildFile ->
get() = BuildSystemPlugin.buildFiles.propertyValue.flatMap { buildFile ->
buildFile.modules.modules
}
val Writer.allModulesPaths
get() = BuildSystemPlugin::buildFiles.propertyValue.flatMap { buildFile ->
get() = BuildSystemPlugin.buildFiles.propertyValue.flatMap { buildFile ->
val paths = when (val structure = buildFile.modules) {
is MultiplatformModulesStructureIR -> listOf(buildFile.directoryPath)
else -> structure.modules.map { it.path }
@@ -189,5 +199,5 @@ val Writer.allModulesPaths
val Reader.buildSystemType: BuildSystemType
get() = BuildSystemPlugin::type.reference.settingValue
get() = BuildSystemPlugin.type.settingValue
@@ -1,14 +1,21 @@
package org.jetbrains.kotlin.tools.projectWizard.plugins.buildSystem
import org.jetbrains.kotlin.tools.projectWizard.core.Context
import org.jetbrains.kotlin.tools.projectWizard.core.entity.PipelineTask
class JpsPlugin(context: Context) : BuildSystemPlugin(context) {
override val path = "buildSystem.jps"
override val path = PATH
val addBuildSystemData by addBuildSystemData(
BuildSystemData(
type = BuildSystemType.Jps,
buildFileData = null
companion object {
private const val PATH = "buildSystem.jps"
val addBuildSystemData by addBuildSystemData(
PATH,
BuildSystemData(
type = BuildSystemType.Jps,
buildFileData = null
)
)
)
}
override val pipelineTasks: List<PipelineTask> = super.pipelineTasks + listOf(addBuildSystemData)
}
@@ -14,56 +14,61 @@ import org.jetbrains.kotlin.tools.projectWizard.plugins.printer.MavenPrinter
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.updateBuildFiles
class MavenPlugin(context: Context) : BuildSystemPlugin(context) {
override val path = "buildSystem.maven"
override val path = PATH
private val isMaven = checker {
BuildSystemPlugin::type.settingValue == BuildSystemType.Maven
}
companion object {
private const val PATH = "buildSystem.maven"
val createSettingsFileTask by pipelineTask(GenerationPhase.PROJECT_GENERATION) {
runAfter(KotlinPlugin::createModules)
runBefore(BuildSystemPlugin::createModules)
isAvailable = isMaven
withAction {
BuildSystemPlugin::buildFiles.update { buildFiles ->
if (buildFiles.size == 1) return@update buildFiles.asSuccess()
buildFiles.map { buildFile ->
when (val structure = buildFile.modules) {
is RootFileModuleStructureIR -> {
val dependencies = allModulesPaths.map { path ->
path.joinToString(separator = "/")
private val isMaven = checker {
type.settingValue == BuildSystemType.Maven
}
val createSettingsFileTask by pipelineTask(PATH, GenerationPhase.PROJECT_GENERATION) {
runAfter(KotlinPlugin.createModules)
runBefore(createModules)
isAvailable = isMaven
withAction {
buildFiles.update { buildFiles ->
if (buildFiles.size == 1) return@update buildFiles.asSuccess()
buildFiles.map { buildFile ->
when (val structure = buildFile.modules) {
is RootFileModuleStructureIR -> {
val dependencies = allModulesPaths.map { path ->
path.joinToString(separator = "/")
}
buildFile.copy(modules = structure.withIrs(ModulesDependencyMavenIR(dependencies)))
}
buildFile.copy(modules = structure.withIrs(ModulesDependencyMavenIR(dependencies)))
else -> buildFile
}
else -> buildFile
}
}.asSuccess()
}.asSuccess()
}
}
}
}
val addBuildSystemPluginRepositories by pipelineTask(GenerationPhase.PROJECT_GENERATION) {
runAfter(KotlinPlugin::createPluginRepositories)
runBefore(BuildSystemPlugin::createModules)
isAvailable = isMaven
val addBuildSystemPluginRepositories by pipelineTask(PATH, GenerationPhase.PROJECT_GENERATION) {
runAfter(KotlinPlugin.createPluginRepositories)
runBefore(createModules)
isAvailable = isMaven
withAction {
val repositories = BuildSystemPlugin::pluginRepositoreis.propertyValue
updateBuildFiles { buildFile ->
buildFile.withIrs(repositories.map(::PluginRepositoryMavenIR)).asSuccess()
withAction {
val repositories = pluginRepositoreis.propertyValue
updateBuildFiles { buildFile ->
buildFile.withIrs(repositories.map(::PluginRepositoryMavenIR)).asSuccess()
}
}
}
}
val addBuildSystemData by addBuildSystemData(
BuildSystemData(
type = BuildSystemType.Maven,
buildFileData = BuildFileData(
createPrinter = { MavenPrinter() },
buildFileName = "pom.xml"
val addBuildSystemData by addBuildSystemData(
PATH,
BuildSystemData(
type = BuildSystemType.Maven,
buildFileData = BuildFileData(
createPrinter = { MavenPrinter() },
buildFileName = "pom.xml"
)
)
)
)
}
override val pipelineTasks: List<PipelineTask> = super.pipelineTasks +
listOf(
@@ -4,8 +4,8 @@ package org.jetbrains.kotlin.tools.projectWizard.plugins.buildSystem.gradle
import org.jetbrains.kotlin.tools.projectWizard.Versions
import org.jetbrains.kotlin.tools.projectWizard.core.*
import org.jetbrains.kotlin.tools.projectWizard.core.entity.PipelineTask
import org.jetbrains.kotlin.tools.projectWizard.core.entity.Property
import org.jetbrains.kotlin.tools.projectWizard.core.entity.settings.PluginSetting
import org.jetbrains.kotlin.tools.projectWizard.core.entity.settings.reference
import org.jetbrains.kotlin.tools.projectWizard.core.service.FileSystemWizardService
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.BuildSystemIR
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.PluginManagementRepositoryIR
@@ -27,111 +27,116 @@ import org.jetbrains.kotlin.tools.projectWizard.templates.FileTemplateDescriptor
abstract class GradlePlugin(context: Context) : BuildSystemPlugin(context) {
override val path = "buildSystem.gradle"
override val path = PATH
val gradleProperties by listProperty(
"kotlin.code.style" to "official"
)
companion object {
private const val PATH = "buildSystem.gradle"
val settingsGradleFileIRs by listProperty<BuildSystemIR>()
val gradleProperties by listProperty(
PATH,
"kotlin.code.style" to "official"
)
val createGradlePropertiesFile by pipelineTask(GenerationPhase.PROJECT_GENERATION) {
runAfter(KotlinPlugin::createModules)
runBefore(TemplatesPlugin::renderFileTemplates)
isAvailable = isGradle
withAction {
TemplatesPlugin::addFileTemplate.execute(
FileTemplate(
FileTemplateDescriptor(
"gradle/gradle.properties.vm",
"gradle.properties".asPath()
),
StructurePlugin::projectPath.settingValue,
mapOf(
"properties" to GradlePlugin::gradleProperties
.propertyValue
.distinctBy { it.first }
val settingsGradleFileIRs by listProperty<BuildSystemIR>(PATH)
val createGradlePropertiesFile by pipelineTask(PATH, GenerationPhase.PROJECT_GENERATION) {
runAfter(KotlinPlugin.createModules)
runBefore(TemplatesPlugin.renderFileTemplates)
isAvailable = isGradle
withAction {
TemplatesPlugin.addFileTemplate.execute(
FileTemplate(
FileTemplateDescriptor(
"gradle/gradle.properties.vm",
"gradle.properties".asPath()
),
StructurePlugin.projectPath.settingValue,
mapOf(
"properties" to gradleProperties
.propertyValue
.distinctBy { it.first }
)
)
)
)
}
}
}
val localProperties by listProperty<Pair<String, String>>()
val localProperties by listProperty<Pair<String, String>>(PATH)
val createLocalPropertiesFile by pipelineTask(GenerationPhase.PROJECT_GENERATION) {
runAfter(KotlinPlugin::createModules)
runBefore(TemplatesPlugin::renderFileTemplates)
isAvailable = isGradle
withAction {
TemplatesPlugin::addFileTemplate.execute(
FileTemplate(
FileTemplateDescriptor(
"gradle/local.properties.vm",
"local.properties".asPath()
),
StructurePlugin::projectPath.settingValue,
mapOf(
"properties" to GradlePlugin::localProperties.propertyValue
val createLocalPropertiesFile by pipelineTask(PATH, GenerationPhase.PROJECT_GENERATION) {
runAfter(KotlinPlugin.createModules)
runBefore(TemplatesPlugin.renderFileTemplates)
isAvailable = isGradle
withAction {
TemplatesPlugin.addFileTemplate.execute(
FileTemplate(
FileTemplateDescriptor(
"gradle/local.properties.vm",
"local.properties".asPath()
),
StructurePlugin.projectPath.settingValue,
mapOf(
"properties" to localProperties.propertyValue
)
)
)
)
}
}
}
private val isGradle = checker { buildSystemType.isGradle }
private val isGradle = checker { buildSystemType.isGradle }
val initGradleWrapperTask by pipelineTask(GenerationPhase.PROJECT_GENERATION) {
runBefore(TemplatesPlugin::renderFileTemplates)
isAvailable = isGradle
withAction {
TemplatesPlugin::addFileTemplate.execute(
FileTemplate(
FileTemplateDescriptor(
"gradle/gradle-wrapper.properties.vm",
"gradle" / "wrapper" / "gradle-wrapper.properties"
),
StructurePlugin::projectPath.reference.settingValue,
mapOf(
"version" to Versions.GRADLE
val initGradleWrapperTask by pipelineTask(PATH, GenerationPhase.PROJECT_GENERATION) {
runBefore(TemplatesPlugin.renderFileTemplates)
isAvailable = isGradle
withAction {
TemplatesPlugin.addFileTemplate.execute(
FileTemplate(
FileTemplateDescriptor(
"gradle/gradle-wrapper.properties.vm",
"gradle" / "wrapper" / "gradle-wrapper.properties"
),
StructurePlugin.projectPath.settingValue,
mapOf(
"version" to Versions.GRADLE
)
)
)
)
}
}
val createSettingsFileTask by pipelineTask(PATH, GenerationPhase.PROJECT_GENERATION) {
runAfter(KotlinPlugin.createModules)
runAfter(KotlinPlugin.createPluginRepositories)
isAvailable = isGradle
withAction {
val (createBuildFile, buildFileName) = settingsGradleBuildFileData ?: return@withAction UNIT_SUCCESS
val repositories = buildList<RepositoryIR> {
+pluginRepositoreis.propertyValue.map(::RepositoryIR)
if (isNotEmpty()) {
+RepositoryIR(DefaultRepository.MAVEN_CENTRAL)
+RepositoryIR(DefaultRepository.GRADLE_PLUGIN_PORTAL)
}
}.map(::PluginManagementRepositoryIR)
val settingsGradleIR = SettingsGradleFileIR(
StructurePlugin.name.settingValue,
allModulesPaths.map { path -> path.joinToString(separator = "") { ":$it" } },
buildPersistenceList {
+repositories
+settingsGradleFileIRs.propertyValue
}
)
val buildFileText = createBuildFile().printBuildFile { settingsGradleIR.render(this) }
service<FileSystemWizardService>().createFile(
projectPath / buildFileName,
buildFileText
)
}
}
}
val createSettingsFileTask by pipelineTask(GenerationPhase.PROJECT_GENERATION) {
runAfter(KotlinPlugin::createModules)
runAfter(KotlinPlugin::createPluginRepositories)
isAvailable = isGradle
withAction {
val (createBuildFile, buildFileName) = settingsGradleBuildFileData ?: return@withAction UNIT_SUCCESS
val repositories = buildList<RepositoryIR> {
+BuildSystemPlugin::pluginRepositoreis.propertyValue.map(::RepositoryIR)
if (isNotEmpty()) {
+RepositoryIR(DefaultRepository.MAVEN_CENTRAL)
+RepositoryIR(DefaultRepository.GRADLE_PLUGIN_PORTAL)
}
}.map(::PluginManagementRepositoryIR)
val settingsGradleIR = SettingsGradleFileIR(
StructurePlugin::name.settingValue,
allModulesPaths.map { path -> path.joinToString(separator = "") { ":$it" } },
buildPersistenceList {
+repositories
+GradlePlugin::settingsGradleFileIRs.propertyValue
}
)
val buildFileText = createBuildFile().printBuildFile { settingsGradleIR.render(this) }
service<FileSystemWizardService>().createFile(
projectPath / buildFileName,
buildFileText
)
}
}
override val settings: List<PluginSetting<*, *>> = super.settings
override val pipelineTasks: List<PipelineTask> = super.pipelineTasks +
listOf(
@@ -140,7 +145,12 @@ abstract class GradlePlugin(context: Context) : BuildSystemPlugin(context) {
initGradleWrapperTask,
createSettingsFileTask,
)
override val properties: List<Property<*>> = super.properties +
listOf(
gradleProperties,
settingsGradleFileIRs,
localProperties
)
}
val Reader.settingsGradleBuildFileData
@@ -8,17 +8,22 @@ import org.jetbrains.kotlin.tools.projectWizard.plugins.buildSystem.BuildSystemT
import org.jetbrains.kotlin.tools.projectWizard.plugins.printer.GradlePrinter
class GroovyDslPlugin(context: Context) : GradlePlugin(context) {
override val path = "buildSystem.gradle.groovyDsl"
override val path = PATH
val addBuildSystemData by addBuildSystemData(
BuildSystemData(
type = BuildSystemType.GradleGroovyDsl,
buildFileData = BuildFileData(
createPrinter = { GradlePrinter(GradlePrinter.GradleDsl.GROOVY) },
buildFileName = "build.gradle"
companion object {
private const val PATH = "buildSystem.gradle.groovyDsl"
val addBuildSystemData by addBuildSystemData(
PATH,
BuildSystemData(
type = BuildSystemType.GradleGroovyDsl,
buildFileData = BuildFileData(
createPrinter = { GradlePrinter(GradlePrinter.GradleDsl.GROOVY) },
buildFileName = "build.gradle"
)
)
)
)
}
override val pipelineTasks: List<PipelineTask> = super.pipelineTasks +
listOf(
@@ -8,17 +8,23 @@ import org.jetbrains.kotlin.tools.projectWizard.plugins.buildSystem.BuildSystemT
import org.jetbrains.kotlin.tools.projectWizard.plugins.printer.GradlePrinter
class KotlinDslPlugin(context: Context) : GradlePlugin(context) {
override val path = "buildSystem.gradle.kotlinDsl"
override val path = PATH
val addBuildSystemData by addBuildSystemData(
BuildSystemData(
type = BuildSystemType.GradleKotlinDsl,
buildFileData = BuildFileData(
createPrinter = { GradlePrinter(GradlePrinter.GradleDsl.KOTLIN) },
buildFileName = "build.gradle.kts"
companion object {
private const val PATH = "buildSystem.gradle.kotlinDsl"
val addBuildSystemData by addBuildSystemData(
PATH,
BuildSystemData(
type = BuildSystemType.GradleKotlinDsl,
buildFileData = BuildFileData(
createPrinter = { GradlePrinter(GradlePrinter.GradleDsl.KOTLIN) },
buildFileName = "build.gradle.kts"
)
)
)
)
}
override val pipelineTasks: List<PipelineTask> = super.pipelineTasks +
listOf(
addBuildSystemData,
@@ -3,10 +3,7 @@ package org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin
import org.jetbrains.kotlin.tools.projectWizard.KotlinNewProjectWizardBundle
import org.jetbrains.kotlin.tools.projectWizard.Versions
import org.jetbrains.kotlin.tools.projectWizard.core.*
import org.jetbrains.kotlin.tools.projectWizard.core.entity.PipelineTask
import org.jetbrains.kotlin.tools.projectWizard.core.entity.ValidationResult
import org.jetbrains.kotlin.tools.projectWizard.core.entity.fold
import org.jetbrains.kotlin.tools.projectWizard.core.entity.settingValidator
import org.jetbrains.kotlin.tools.projectWizard.core.entity.*
import org.jetbrains.kotlin.tools.projectWizard.core.entity.settings.PluginSetting
import org.jetbrains.kotlin.tools.projectWizard.core.service.*
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.BuildFileIR
@@ -21,128 +18,14 @@ import org.jetbrains.kotlin.tools.projectWizard.plugins.pomIR
import org.jetbrains.kotlin.tools.projectWizard.plugins.projectPath
import org.jetbrains.kotlin.tools.projectWizard.settings.DisplayableSettingItem
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.*
import org.jetbrains.kotlin.tools.projectWizard.settings.version.Version
import java.nio.file.Path
class KotlinPlugin(context: Context) : Plugin(context) {
override val path = "kotlin"
val version by property(
// todo do not hardcode kind & repository
WizardKotlinVersion(Versions.KOTLIN, KotlinVersionKind.M, Repositories.KOTLIN_EAP_BINTRAY)
)
val initKotlinVersions by pipelineTask(GenerationPhase.PREPARE_GENERATION) {
title = KotlinNewProjectWizardBundle.message("plugin.kotlin.downloading.kotlin.versions")
withAction {
val version = service<KotlinVersionProviderService>().getKotlinVersion()
KotlinPlugin::version.update { version.asSuccess() }
}
}
val projectKind by enumSetting<ProjectKind>(
KotlinNewProjectWizardBundle.message("plugin.kotlin.setting.project.kind"),
GenerationPhase.FIRST_STEP
)
private fun List<Module>.findDuplicatesByName() =
groupingBy { it.name }.eachCount().filter { it.value > 1 }
val modules by listSetting(
KotlinNewProjectWizardBundle.message("plugin.kotlin.setting.modules"),
GenerationPhase.SECOND_STEP,
Module.parser
) {
validate { value ->
val allModules = value.withAllSubModules()
val duplicatedModules = allModules.findDuplicatesByName()
if (duplicatedModules.isEmpty()) ValidationResult.OK
else ValidationResult.ValidationError(
KotlinNewProjectWizardBundle.message(
"plugin.kotlin.setting.modules.error.duplicated.modules",
duplicatedModules.values.first(),
duplicatedModules.keys.first()
)
)
}
validate { value ->
value.withAllSubModules().filter { it.kind == ModuleKind.multiplatform }.map { module ->
val duplicatedModules = module.subModules.findDuplicatesByName()
if (duplicatedModules.isEmpty()) ValidationResult.OK
else ValidationResult.ValidationError(
KotlinNewProjectWizardBundle.message(
"plugin.kotlin.setting.modules.error.duplicated.targets",
duplicatedModules.values.first(),
duplicatedModules.keys.first()
)
)
}.fold()
}
validate(moduleDependenciesValidator)
}
val createModules by pipelineTask(GenerationPhase.PROJECT_GENERATION) {
runBefore(BuildSystemPlugin::createModules)
runAfter(StructurePlugin::createProjectDir)
withAction {
BuildSystemPlugin::buildFiles.update {
val modules = KotlinPlugin::modules.settingValue
val (buildFiles) = createBuildFiles(modules)
buildFiles.map { it.withIrs(RepositoryIR(DefaultRepository.MAVEN_CENTRAL)) }.asSuccess()
}
}
}
val createPluginRepositories by pipelineTask(GenerationPhase.PROJECT_GENERATION) {
runBefore(BuildSystemPlugin::createModules)
withAction {
val version = KotlinPlugin::version.propertyValue
if (version.kind.isStable) return@withAction UNIT_SUCCESS
val pluginRepository = version.repository
BuildSystemPlugin::pluginRepositoreis.addValues(pluginRepository) andThen
updateBuildFiles { buildFile ->
buildFile.withIrs(RepositoryIR(pluginRepository)).asSuccess()
}
}
}
val createSourcesetDirectories by pipelineTask(GenerationPhase.PROJECT_GENERATION) {
runAfter(KotlinPlugin::createModules)
withAction {
fun Path.createKotlinAndResourceDirectories(moduleConfigurator: ModuleConfigurator) = with(service<FileSystemWizardService>()) {
createDirectory(this@createKotlinAndResourceDirectories / moduleConfigurator.kotlinDirectoryName) andThen
createDirectory(this@createKotlinAndResourceDirectories / moduleConfigurator.resourcesDirectoryName)
}
forEachModule { moduleIR ->
moduleIR.sourcesets.mapSequenceIgnore { sourcesetIR ->
sourcesetIR.path.createKotlinAndResourceDirectories(moduleIR.originalModule.configurator)
}
}
}
}
private fun Writer.createBuildFiles(modules: List<Module>): TaskResult<List<BuildFileIR>> =
with(
ModulesToIRsConverter(
ModulesToIrConversionData(
modules,
projectPath,
StructurePlugin::name.settingValue,
KotlinPlugin::version.propertyValue,
buildSystemType,
pomIR()
)
)
) { createBuildFiles() }
override val path = PATH
companion object {
private const val PATH = "kotlin"
private val moduleDependenciesValidator = settingValidator<List<Module>> { modules ->
val allModules = modules.withAllSubModules(includeSourcesets = true).toSet()
val allModulePaths = allModules.map(Module::path).toSet()
@@ -162,6 +45,122 @@ class KotlinPlugin(context: Context) : Plugin(context) {
}
}.fold()
}
val version by property(
PATH,
// todo do not hardcode kind & repository
WizardKotlinVersion(Versions.KOTLIN, KotlinVersionKind.M, Repositories.KOTLIN_EAP_BINTRAY)
)
val initKotlinVersions by pipelineTask(PATH, GenerationPhase.PREPARE_GENERATION) {
title = KotlinNewProjectWizardBundle.message("plugin.kotlin.downloading.kotlin.versions")
withAction {
val version = service<KotlinVersionProviderService>().getKotlinVersion()
KotlinPlugin.version.update { version.asSuccess() }
}
}
val projectKind by enumSetting<ProjectKind>(
KotlinNewProjectWizardBundle.message("plugin.kotlin.setting.project.kind"),
GenerationPhase.FIRST_STEP,
PATH
)
private fun List<Module>.findDuplicatesByName() =
groupingBy { it.name }.eachCount().filter { it.value > 1 }
val modules by listSetting(
KotlinNewProjectWizardBundle.message("plugin.kotlin.setting.modules"),
GenerationPhase.SECOND_STEP,
Module.parser,
PATH
) {
validate { value ->
val allModules = value.withAllSubModules()
val duplicatedModules = allModules.findDuplicatesByName()
if (duplicatedModules.isEmpty()) ValidationResult.OK
else ValidationResult.ValidationError(
KotlinNewProjectWizardBundle.message(
"plugin.kotlin.setting.modules.error.duplicated.modules",
duplicatedModules.values.first(),
duplicatedModules.keys.first()
)
)
}
validate { value ->
value.withAllSubModules().filter { it.kind == ModuleKind.multiplatform }.map { module ->
val duplicatedModules = module.subModules.findDuplicatesByName()
if (duplicatedModules.isEmpty()) ValidationResult.OK
else ValidationResult.ValidationError(
KotlinNewProjectWizardBundle.message(
"plugin.kotlin.setting.modules.error.duplicated.targets",
duplicatedModules.values.first(),
duplicatedModules.keys.first()
)
)
}.fold()
}
validate(moduleDependenciesValidator)
}
val createModules by pipelineTask(PATH, GenerationPhase.PROJECT_GENERATION) {
runBefore(BuildSystemPlugin.createModules)
runAfter(StructurePlugin.createProjectDir)
withAction {
BuildSystemPlugin.buildFiles.update {
val modules = modules.settingValue
val (buildFiles) = createBuildFiles(modules)
buildFiles.map { it.withIrs(RepositoryIR(DefaultRepository.MAVEN_CENTRAL)) }.asSuccess()
}
}
}
val createPluginRepositories by pipelineTask(PATH, GenerationPhase.PROJECT_GENERATION) {
runBefore(BuildSystemPlugin.createModules)
withAction {
val version = version.propertyValue
if (version.kind.isStable) return@withAction UNIT_SUCCESS
val pluginRepository = version.repository
BuildSystemPlugin.pluginRepositoreis.addValues(pluginRepository) andThen
updateBuildFiles { buildFile ->
buildFile.withIrs(RepositoryIR(pluginRepository)).asSuccess()
}
}
}
val createSourcesetDirectories by pipelineTask(PATH, GenerationPhase.PROJECT_GENERATION) {
runAfter(KotlinPlugin.createModules)
withAction {
fun Path.createKotlinAndResourceDirectories(moduleConfigurator: ModuleConfigurator) =
with(service<FileSystemWizardService>()) {
createDirectory(this@createKotlinAndResourceDirectories / moduleConfigurator.kotlinDirectoryName) andThen
createDirectory(this@createKotlinAndResourceDirectories / moduleConfigurator.resourcesDirectoryName)
}
forEachModule { moduleIR ->
moduleIR.sourcesets.mapSequenceIgnore { sourcesetIR ->
sourcesetIR.path.createKotlinAndResourceDirectories(moduleIR.originalModule.configurator)
}
}
}
}
private fun Writer.createBuildFiles(modules: List<Module>): TaskResult<List<BuildFileIR>> =
with(
ModulesToIRsConverter(
ModulesToIrConversionData(
modules,
projectPath,
StructurePlugin.name.settingValue,
version.propertyValue,
buildSystemType,
pomIR()
)
)
) { createBuildFiles() }
}
override val settings: List<PluginSetting<*, *>> =
@@ -177,6 +176,8 @@ class KotlinPlugin(context: Context) : Plugin(context) {
createPluginRepositories,
createSourcesetDirectories
)
override val properties: List<Property<*>> =
listOf(version)
}
@@ -253,9 +253,9 @@ class ModulesToIRsConverter(
compute {
rootBuildFileIrs += createRootBuildFileIrs(data)
runArbitraryTask(data, module, modulePath).ensure()
TemplatesPlugin::addFileTemplates.execute(createTemplates(data, module, modulePath)).ensure()
TemplatesPlugin.addFileTemplates.execute(createTemplates(data, module, modulePath)).ensure()
if (this@with is GradleModuleConfigurator) {
GradlePlugin::settingsGradleFileIRs.addValues(createSettingsGradleIRs(module)).ensure()
GradlePlugin.settingsGradleFileIRs.addValues(createSettingsGradleIRs(module)).ensure()
}
}
}
@@ -3,6 +3,7 @@ package org.jetbrains.kotlin.tools.projectWizard.plugins.projectTemplates
import org.jetbrains.kotlin.tools.projectWizard.KotlinNewProjectWizardBundle
import org.jetbrains.kotlin.tools.projectWizard.core.*
import org.jetbrains.kotlin.tools.projectWizard.core.entity.PipelineTask
import org.jetbrains.kotlin.tools.projectWizard.core.entity.Property
import org.jetbrains.kotlin.tools.projectWizard.core.entity.settings.PluginSetting
import org.jetbrains.kotlin.tools.projectWizard.phases.GenerationPhase
@@ -11,28 +12,34 @@ import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.withAllSubModules
import org.jetbrains.kotlin.tools.projectWizard.projectTemplates.ProjectTemplate
class ProjectTemplatesPlugin(context: Context) : Plugin(context) {
override val path = "projectTemplates"
override val path = PATH
val template by dropDownSetting<ProjectTemplate>(
KotlinNewProjectWizardBundle.message("plugin.templates.setting.template"),
GenerationPhase.INIT_TEMPLATE,
parser = valueParserM { _, _ ->
Failure(ParseError("Project templates is not supported in yaml for now"))
companion object {
const val PATH = "projectTemplates"
val template by dropDownSetting<ProjectTemplate>(
KotlinNewProjectWizardBundle.message("plugin.templates.setting.template"),
GenerationPhase.INIT_TEMPLATE,
parser = valueParserM { _, _ ->
Failure(ParseError("Project templates is not supported in yaml for now"))
},
PATH
) {
values = ProjectTemplate.ALL
isRequired = false
}
) {
values = ProjectTemplate.ALL
isRequired = false
}
override val settings: List<PluginSetting<*, *>> = listOf(template)
override val pipelineTasks: List<PipelineTask> = listOf()
override val properties: List<Property<*>> = listOf()
}
fun SettingsWriter.applyProjectTemplate(projectTemplate: ProjectTemplate) {
projectTemplate.setsValues.forEach { (setting, value) ->
setting.setValue(value)
}
KotlinPlugin::modules.settingValue.withAllSubModules(includeSourcesets = true).forEach { module ->
KotlinPlugin.modules.settingValue.withAllSubModules(includeSourcesets = true).forEach { module ->
module.apply { initDefaultValuesForSettings() }
}
}
@@ -1,12 +1,17 @@
package org.jetbrains.kotlin.tools.projectWizard.plugins.templates
import org.jetbrains.kotlin.tools.projectWizard.core.Context
import org.jetbrains.kotlin.tools.projectWizard.core.entity.PipelineTask
import org.jetbrains.kotlin.tools.projectWizard.templates.ConsoleJvmApplicationTemplate
class ConsoleJvmApplicationTemplatePlugin(context: Context) : TemplatePlugin(context) {
override val path = "template.consoleJvmApplicationTemplate"
override val path = PATH
val addTemplate by addTemplateTask(
ConsoleJvmApplicationTemplate()
)
override val pipelineTasks: List<PipelineTask> = super.pipelineTasks + listOf(addTemplate)
companion object {
private const val PATH = "template.consoleJvmApplicationTemplate"
val addTemplate by addTemplateTask(PATH, ConsoleJvmApplicationTemplate())
}
}
@@ -5,12 +5,16 @@ import org.jetbrains.kotlin.tools.projectWizard.core.entity.PipelineTask
import org.jetbrains.kotlin.tools.projectWizard.templates.SimpleJsClientTemplate
class JsTemplatesPlugin(context: Context) : TemplatePlugin(context) {
override val path = "template.jsTemplate"
val addTemplate by addTemplateTask(SimpleJsClientTemplate())
override val path = PATH
override val pipelineTasks: List<PipelineTask> = super.pipelineTasks +
listOf(
addTemplate,
)
companion object {
private const val PATH = "template.jsTemplates"
val addTemplate by addTemplateTask(PATH, SimpleJsClientTemplate())
}
}
@@ -5,10 +5,16 @@ import org.jetbrains.kotlin.tools.projectWizard.core.entity.PipelineTask
import org.jetbrains.kotlin.tools.projectWizard.templates.KtorServerTemplate
class KtorTemplatesPlugin(context: Context) : TemplatePlugin(context) {
val addTemplate by addTemplateTask(KtorServerTemplate())
override val path = PATH
override val pipelineTasks: List<PipelineTask> = super.pipelineTasks +
listOf(
addTemplate,
)
companion object {
private const val PATH = "template.ktorTemplates"
val addTemplate by addTemplateTask(PATH, KtorServerTemplate())
}
}
@@ -10,10 +10,16 @@ import org.jetbrains.kotlin.tools.projectWizard.core.entity.PipelineTask
import org.jetbrains.kotlin.tools.projectWizard.templates.NativeConsoleApplicationTemplate
class NativeConsoleApplicationTemplatePlugin(context: Context) : TemplatePlugin(context) {
val addTemplate by addTemplateTask(NativeConsoleApplicationTemplate())
override val path = PATH
override val pipelineTasks: List<PipelineTask> = super.pipelineTasks +
listOf(
addTemplate,
)
companion object {
private const val PATH = "template.nativeConsoleApplicationTemplate"
val addTemplate by addTemplateTask(PATH, NativeConsoleApplicationTemplate())
}
}
@@ -3,19 +3,25 @@ package org.jetbrains.kotlin.tools.projectWizard.plugins.templates
import org.jetbrains.kotlin.tools.projectWizard.core.Context
import org.jetbrains.kotlin.tools.projectWizard.core.Plugin
import org.jetbrains.kotlin.tools.projectWizard.core.entity.PipelineTask
import org.jetbrains.kotlin.tools.projectWizard.core.entity.Property
import org.jetbrains.kotlin.tools.projectWizard.core.entity.settings.PluginSetting
import org.jetbrains.kotlin.tools.projectWizard.phases.GenerationPhase
import org.jetbrains.kotlin.tools.projectWizard.templates.Template
abstract class TemplatePlugin(context: Context) : Plugin(context) {
override val path = "template"
fun addTemplateTask(template: Template) = pipelineTask(GenerationPhase.PREPARE) {
withAction {
TemplatesPlugin::addTemplate.execute(template)
}
}
override val path = PATH
override val settings: List<PluginSetting<*, *>> = emptyList()
override val pipelineTasks: List<PipelineTask> = emptyList()
override val properties: List<Property<*>> = emptyList()
companion object {
const val PATH = "template"
fun addTemplateTask(prefix: String, template: Template) = pipelineTask(prefix, GenerationPhase.PREPARE) {
withAction {
TemplatesPlugin.addTemplate.execute(template)
}
}
}
}
@@ -4,6 +4,7 @@ package org.jetbrains.kotlin.tools.projectWizard.plugins.templates
import org.jetbrains.kotlin.tools.projectWizard.core.*
import org.jetbrains.kotlin.tools.projectWizard.core.Defaults.SRC_DIR
import org.jetbrains.kotlin.tools.projectWizard.core.entity.PipelineTask
import org.jetbrains.kotlin.tools.projectWizard.core.entity.Property
import org.jetbrains.kotlin.tools.projectWizard.core.entity.settings.PluginSetting
import org.jetbrains.kotlin.tools.projectWizard.core.service.TemplateEngineService
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.*
@@ -23,144 +24,149 @@ import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.settingValue
import java.nio.file.Path
class TemplatesPlugin(context: Context) : Plugin(context) {
override val path = "templates"
override val path = PATH
val templates by property<Map<String, Template>>(
emptyMap()
)
companion object {
private const val PATH = "templates"
val addTemplate by task1<Template, Unit> {
withAction { template ->
TemplatesPlugin::templates.update { success(it + (template.id to template)) }
}
}
val templates by property<Map<String, Template>>(
PATH,
emptyMap()
)
val fileTemplatesToRender by property<List<FileTemplate>>(emptyList())
val addFileTemplate by task1<FileTemplate, Unit> {
withAction { template ->
TemplatesPlugin::fileTemplatesToRender.update { success(it + template) }
}
}
val addFileTemplates by task1<List<FileTemplate>, Unit> {
withAction { templates ->
TemplatesPlugin::fileTemplatesToRender.addValues(templates)
}
}
val renderFileTemplates by pipelineTask(GenerationPhase.PROJECT_GENERATION) {
runAfter(KotlinPlugin::createModules)
withAction {
val templateEngine = service<TemplateEngineService>()
TemplatesPlugin::fileTemplatesToRender.propertyValue.mapSequenceIgnore { template ->
with(templateEngine) { writeTemplate(template) }
val addTemplate by task1<Template, Unit>(PATH) {
withAction { template ->
templates.update { success(it + (template.id to template)) }
}
}
}
val addTemplatesToModules by pipelineTask(GenerationPhase.PROJECT_GENERATION) {
runBefore(BuildSystemPlugin::createModules)
runAfter(KotlinPlugin::createModules)
val fileTemplatesToRender by property<List<FileTemplate>>(PATH, emptyList())
withAction {
updateBuildFiles { buildFile ->
buildFile.modules.modules.mapSequence { module ->
applyTemplateToModule(
module.template,
module
).map { result -> module.withIrs(result.librariesToAdd) to result }
}.map {
val (moduleIrs, results) = it.unzip()
val foldedResults = results.fold()
buildFile.copy(
modules = buildFile.modules.withModules(moduleIrs)
).withIrs(foldedResults.irsToAddToBuildFile).let { buildFile ->
when (val structure = buildFile.modules) {
is MultiplatformModulesStructureIR ->
buildFile.copy(modules = structure.updateTargets(foldedResults.updateTarget))
else -> buildFile
val addFileTemplate by task1<FileTemplate, Unit>(PATH) {
withAction { template ->
fileTemplatesToRender.update { success(it + template) }
}
}
val addFileTemplates by task1<List<FileTemplate>, Unit>(PATH) {
withAction { templates ->
fileTemplatesToRender.addValues(templates)
}
}
val renderFileTemplates by pipelineTask(PATH, GenerationPhase.PROJECT_GENERATION) {
runAfter(KotlinPlugin.createModules)
withAction {
val templateEngine = service<TemplateEngineService>()
fileTemplatesToRender.propertyValue.mapSequenceIgnore { template ->
with(templateEngine) { writeTemplate(template) }
}
}
}
val addTemplatesToModules by pipelineTask(PATH, GenerationPhase.PROJECT_GENERATION) {
runBefore(BuildSystemPlugin.createModules)
runAfter(KotlinPlugin.createModules)
withAction {
updateBuildFiles { buildFile ->
buildFile.modules.modules.mapSequence { module ->
applyTemplateToModule(
module.template,
module
).map { result -> module.withIrs(result.librariesToAdd) to result }
}.map {
val (moduleIrs, results) = it.unzip()
val foldedResults = results.fold()
buildFile.copy(
modules = buildFile.modules.withModules(moduleIrs)
).withIrs(foldedResults.irsToAddToBuildFile).let { buildFile ->
when (val structure = buildFile.modules) {
is MultiplatformModulesStructureIR ->
buildFile.copy(modules = structure.updateTargets(foldedResults.updateTarget))
else -> buildFile
}
}
}
}
}
}
}
val postApplyTemplatesToModules by pipelineTask(GenerationPhase.PROJECT_GENERATION) {
runBefore(BuildSystemPlugin::createModules)
runAfter(KotlinPlugin::createModules)
runAfter(TemplatesPlugin::addTemplatesToModules)
val postApplyTemplatesToModules by pipelineTask(PATH, GenerationPhase.PROJECT_GENERATION) {
runBefore(BuildSystemPlugin.createModules)
runAfter(KotlinPlugin.createModules)
runAfter(TemplatesPlugin.addTemplatesToModules)
withAction {
updateBuildFiles { buildFile ->
val modules = buildFile.modules.modules
withAction {
updateBuildFiles { buildFile ->
val modules = buildFile.modules.modules
val applicationState = modules.mapNotNull { module ->
module.template?.createInterceptors(module)
}.flatten()
.applyAll(TemplateInterceptionApplicationState(buildFile, emptyMap()))
val applicationState = modules.mapNotNull { module ->
module.template?.createInterceptors(module)
}.flatten()
.applyAll(TemplateInterceptionApplicationState(buildFile, emptyMap()))
val templateEngine = service<TemplateEngineService>()
val templateEngine = service<TemplateEngineService>()
val templatesApplicationResult = modules.map { module ->
val settings = applicationState.moduleToSettings[module.originalModule.identificator].orEmpty()
applyFileTemplatesFromSourceset(module, templateEngine, settings)
}.sequenceIgnore()
val templatesApplicationResult = modules.map { module ->
val settings = applicationState.moduleToSettings[module.originalModule.identificator].orEmpty()
applyFileTemplatesFromSourceset(module, templateEngine, settings)
}.sequenceIgnore()
templatesApplicationResult andThen applicationState.buildFileIR.asSuccess()
}
}
}
private fun Writer.applyFileTemplatesFromSourceset(
module: ModuleIR,
templateEngine: TemplateEngineService,
interceptionPointSettings: Map<InterceptionPoint<Any>, Any>
): TaskResult<Unit> {
val template = module.template ?: return UNIT_SUCCESS
val settings = with(template) { settingsAsMap(module.originalModule) }
val allSettings: Map<String, Any> = mutableMapOf<String, Any>().apply {
putAll(settings)
putAll(interceptionPointSettings.mapKeys { it.key.name })
putAll(defaultSettings(module))
}
return with(template) { getFileTemplates(module) }.mapNotNull { (fileTemplateDescriptor, filePath) ->
val path = generatePathForFileTemplate(module, filePath) ?: return@mapNotNull null
val fileTemplate = FileTemplate(
fileTemplateDescriptor,
module.path / path,
allSettings
)
with(templateEngine) { writeTemplate(fileTemplate) }
}.sequenceIgnore()
}
private fun Reader.defaultSettings(moduleIR: ModuleIR) = mapOf(
"projectName" to projectName,
"moduleName" to moduleIR.name
)
private fun Reader.generatePathForFileTemplate(module: ModuleIR, filePath: FilePath): Path? {
if (filePath is SrcFilePath
&& filePath.sourcesetType == SourcesetType.test
&& settingValue(module.originalModule, ModuleConfiguratorWithTests.testFramework)?.isPresent != true
) return null
val moduleConfigurator = module.originalModule.configurator
return when (module) {
is SingleplatformModuleIR -> {
when (filePath) {
is SrcFilePath -> SRC_DIR / filePath.sourcesetType.toString() / moduleConfigurator.kotlinDirectoryName
is ResourcesFilePath -> SRC_DIR / filePath.sourcesetType.toString() / moduleConfigurator.resourcesDirectoryName
templatesApplicationResult andThen applicationState.buildFileIR.asSuccess()
}
}
}
is MultiplatformModuleIR -> {
val directory = when (filePath) {
is SrcFilePath -> moduleConfigurator.kotlinDirectoryName
is ResourcesFilePath -> moduleConfigurator.resourcesDirectoryName
private fun Writer.applyFileTemplatesFromSourceset(
module: ModuleIR,
templateEngine: TemplateEngineService,
interceptionPointSettings: Map<InterceptionPoint<Any>, Any>
): TaskResult<Unit> {
val template = module.template ?: return UNIT_SUCCESS
val settings = with(template) { settingsAsMap(module.originalModule) }
val allSettings: Map<String, Any> = mutableMapOf<String, Any>().apply {
putAll(settings)
putAll(interceptionPointSettings.mapKeys { it.key.name })
putAll(defaultSettings(module))
}
return with(template) { getFileTemplates(module) }.mapNotNull { (fileTemplateDescriptor, filePath) ->
val path = generatePathForFileTemplate(module, filePath) ?: return@mapNotNull null
val fileTemplate = FileTemplate(
fileTemplateDescriptor,
module.path / path,
allSettings
)
with(templateEngine) { writeTemplate(fileTemplate) }
}.sequenceIgnore()
}
private fun Reader.defaultSettings(moduleIR: ModuleIR) = mapOf(
"projectName" to projectName,
"moduleName" to moduleIR.name
)
private fun Reader.generatePathForFileTemplate(module: ModuleIR, filePath: FilePath): Path? {
if (filePath is SrcFilePath
&& filePath.sourcesetType == SourcesetType.test
&& settingValue(module.originalModule, ModuleConfiguratorWithTests.testFramework)?.isPresent != true
) return null
val moduleConfigurator = module.originalModule.configurator
return when (module) {
is SingleplatformModuleIR -> {
when (filePath) {
is SrcFilePath -> SRC_DIR / filePath.sourcesetType.toString() / moduleConfigurator.kotlinDirectoryName
is ResourcesFilePath -> SRC_DIR / filePath.sourcesetType.toString() / moduleConfigurator.resourcesDirectoryName
}
}
is MultiplatformModuleIR -> {
val directory = when (filePath) {
is SrcFilePath -> moduleConfigurator.kotlinDirectoryName
is ResourcesFilePath -> moduleConfigurator.resourcesDirectoryName
}
SRC_DIR / "${module.name}${filePath.sourcesetType.name.capitalize()}" / directory
}
SRC_DIR / "${module.name}${filePath.sourcesetType.name.capitalize()}" / directory
}
}
}
@@ -172,4 +178,9 @@ class TemplatesPlugin(context: Context) : Plugin(context) {
addTemplatesToModules,
postApplyTemplatesToModules
)
override val properties: List<Property<*>> =
listOf(
templates,
fileTemplatesToRender
)
}
@@ -27,7 +27,7 @@ sealed class ProjectTemplate : DisplayableSettingItem {
abstract val id: String
private val setsDefaultValues: List<SettingWithValue<*, *>>
get() = listOf(KotlinPlugin::projectKind.reference withValue projectKind)
get() = listOf(KotlinPlugin.projectKind.reference withValue projectKind)
protected open val setsPluginSettings: List<SettingWithValue<*, *>> = emptyList()
protected open val setsModules: List<Module> = emptyList()
@@ -36,7 +36,7 @@ sealed class ProjectTemplate : DisplayableSettingItem {
val setsValues: List<SettingWithValue<*, *>>
get() = buildList {
setsModules.takeIf { it.isNotEmpty() }?.let { modules ->
+(KotlinPlugin::modules withValue modules)
+(KotlinPlugin.modules.reference withValue modules)
}
+setsDefaultValues
+setsPluginSettings
@@ -123,10 +123,6 @@ data class SettingWithValue<V : Any, T : SettingType<V>>(val setting: SettingRef
infix fun <V : Any, T : SettingType<V>> PluginSettingReference<V, T>.withValue(value: V): SettingWithValue<V, T> =
SettingWithValue(this, value)
inline infix fun <V : Any, reified T : SettingType<V>> PluginSettingPropertyReference<V, T>.withValue(
value: V
): SettingWithValue<V, T> = reference.withValue(value)
private fun createDefaultSourcesets() =
SourcesetType.values().map { sourcesetType ->
Sourceset(
@@ -150,7 +146,7 @@ object BackendApplicationProjectTemplate : ProjectTemplate() {
override val setsPluginSettings: List<SettingWithValue<*, *>>
get() = listOf(
KotlinPlugin::modules withValue listOf(
KotlinPlugin.modules.reference withValue listOf(
SingleplatformModule("mainModule", createDefaultSourcesets())
)
)
@@ -167,7 +163,7 @@ object MultiplatformApplicationProjectTemplate : ProjectTemplate() {
override val setsPluginSettings: List<SettingWithValue<*, *>>
get() = listOf(
KotlinPlugin::modules withValue listOf(
KotlinPlugin.modules.reference withValue listOf(
MultiplatformModule("mainModule", listOf(ModuleType.common.createDefaultTarget()))
)
)
@@ -184,7 +180,7 @@ object ConsoleApplicationProjectTemplate : ProjectTemplate() {
override val setsPluginSettings: List<SettingWithValue<*, *>>
get() = listOf(
KotlinPlugin::modules withValue listOf(
KotlinPlugin.modules.reference withValue listOf(
SingleplatformModule(
"consoleApp",
createDefaultSourcesets()
@@ -206,7 +202,7 @@ object MultiplatformLibraryProjectTemplate : ProjectTemplate() {
override val setsPluginSettings: List<SettingWithValue<*, *>>
get() = listOf(
KotlinPlugin::modules withValue listOf(
KotlinPlugin.modules.reference withValue listOf(
MultiplatformModule(
"library",
listOf(
@@ -231,7 +227,7 @@ object FullStackWebApplicationProjectTemplate : ProjectTemplate() {
override val suggestedProjectName: String = "myFullStackApplication"
override val projectKind: ProjectKind = ProjectKind.Multiplatform
override val setsPluginSettings: List<SettingWithValue<*, *>> = listOf(
KotlinPlugin::modules withValue listOf(
KotlinPlugin.modules.reference withValue listOf(
MultiplatformModule(
"application",
listOf(
@@ -261,7 +257,7 @@ object NativeApplicationProjectTemplate : ProjectTemplate() {
override val setsPluginSettings: List<SettingWithValue<*, *>>
get() = listOf(
KotlinPlugin::modules withValue listOf(
KotlinPlugin.modules.reference withValue listOf(
Module(
"app",
MppModuleConfigurator,
@@ -288,7 +284,7 @@ object FrontendApplicationProjectTemplate : ProjectTemplate() {
override val setsPluginSettings: List<SettingWithValue<*, *>>
get() = listOf(
KotlinPlugin::modules withValue listOf(
KotlinPlugin.modules.reference withValue listOf(
Module(
"frontend",
BrowserJsSinglePlatformModuleConfigurator,
@@ -365,7 +361,7 @@ object MultiplatformMobileLibraryProjectTemplate : ProjectTemplate() {
override val setsPluginSettings: List<SettingWithValue<*, *>>
get() = listOf(
KotlinPlugin::modules withValue listOf(
KotlinPlugin.modules.reference withValue listOf(
MultiplatformModule(
"library",
listOf(
@@ -87,7 +87,7 @@ sealed class ModuleDependencyType(
IOSSinglePlatformModuleConfigurator.dependentModule.reference
.setValue(IOSSinglePlatformModuleConfigurator.DependentModuleReference(to))
val dummyFilePath = Defaults.SRC_DIR / "${to.iosTargetSafe()!!.name}Main" / to.configurator.kotlinDirectoryName / "dummyFile.kt"
TemplatesPlugin::addFileTemplate.execute(
TemplatesPlugin.addFileTemplate.execute(
FileTemplate(
FileTemplateDescriptor("ios/dummyFile.kt", dummyFilePath),
projectPath / toModulePath
@@ -85,7 +85,7 @@ enum class SourcesetType : DisplayableSettingItem {
fun Writer.updateBuildFiles(action: (BuildFileIR) -> TaskResult<BuildFileIR>): TaskResult<Unit> =
BuildSystemPlugin::buildFiles.update { buildFiles ->
BuildSystemPlugin.buildFiles.update { buildFiles ->
buildFiles.mapSequence(action)
}
@@ -41,13 +41,13 @@ class KtorServerTemplate : Template() {
override fun Writer.getRequiredLibraries(module: ModuleIR): List<DependencyIR> =
withSettingsOf(module.originalModule) {
val kotlinVersion = KotlinPlugin::version.propertyValue.version
val kotlinVersion = KotlinPlugin.version.propertyValue.version
buildList {
+ktorArtifactDependency(serverEngine.reference.settingValue.dependencyName, kotlinVersion)
+ktorArtifactDependency("ktor-html-builder", kotlinVersion)
+ArtifactBasedLibraryDependencyIR(
MavenArtifact(Repositories.KOTLINX, "org.jetbrains.kotlinx", "kotlinx-html-jvm"),
Versions.KOTLINX.KOTLINX_HTML(KotlinPlugin::version.propertyValue.version),
Versions.KOTLINX.KOTLINX_HTML(KotlinPlugin.version.propertyValue.version),
DependencyType.MAIN
)
}
@@ -81,11 +81,11 @@ class SimpleJsClientTemplate : Template() {
buildList {
+ArtifactBasedLibraryDependencyIR(
MavenArtifact(Repositories.KOTLINX, "org.jetbrains.kotlinx", "kotlinx-html-js"),
Versions.KOTLINX.KOTLINX_HTML(KotlinPlugin::version.propertyValue.version),
Versions.KOTLINX.KOTLINX_HTML(KotlinPlugin.version.propertyValue.version),
DependencyType.MAIN
)
val kotlinVersion = KotlinPlugin::version.propertyValue
val kotlinVersion = KotlinPlugin.version.propertyValue
if (renderEngine.reference.settingValue != RenderEngine.KOTLINX_HTML) {
+Dependencies.KOTLIN_REACT(kotlinVersion.version)
+Dependencies.KOTLIN_REACT_DOM(kotlinVersion.version)
@@ -66,6 +66,7 @@ fun <V : Any, T : SettingType<V>> Reader.settingValue(module: Module, setting: T
abstract class Template : SettingsOwner, EntitiesOwnerDescriptor, DisplayableSettingItem {
final override fun <V : Any, T : SettingType<V>> settingDelegate(
prefix: String,
create: (path: String) -> SettingBuilder<V, T>
): ReadOnlyProperty<Any, TemplateSetting<V, T>> = cached { name ->
TemplateSetting(create(name).buildInternal())
@@ -126,7 +127,7 @@ abstract class Template : SettingsOwner, EntitiesOwnerDescriptor, DisplayableSet
else -> idFunction()
}
RunConfigurationsPlugin::configurations.addValues(createRunConfigurations(module))
RunConfigurationsPlugin.configurations.addValues(createRunConfigurations(module))
val result = TemplateApplicationResult(librariesToAdd, irsToAddToBuildFile, targetsUpdater)
return result.asSuccess()
@@ -144,7 +145,7 @@ abstract class Template : SettingsOwner, EntitiesOwnerDescriptor, DisplayableSet
private fun Reader.createDefaultSettings() = mapOf(
"projectName" to StructurePlugin::name.settingValue.capitalize()
"projectName" to StructurePlugin.name.settingValue.capitalize()
)
override fun equals(other: Any?): Boolean =
@@ -157,12 +158,14 @@ abstract class Template : SettingsOwner, EntitiesOwnerDescriptor, DisplayableSet
title: String,
neededAtPhase: GenerationPhase,
parser: Parser<V>,
prefix: String,
init: DropDownSettingType.Builder<V>.() -> Unit
): ReadOnlyProperty<Any, TemplateSetting<V, DropDownSettingType<V>>> =
super.dropDownSetting(
title,
neededAtPhase,
parser,
prefix,
init
) as ReadOnlyProperty<Any, TemplateSetting<V, DropDownSettingType<V>>>
@@ -170,11 +173,13 @@ abstract class Template : SettingsOwner, EntitiesOwnerDescriptor, DisplayableSet
final override fun stringSetting(
title: String,
neededAtPhase: GenerationPhase,
prefix: String,
init: StringSettingType.Builder.() -> Unit
): ReadOnlyProperty<Any, TemplateSetting<String, StringSettingType>> =
super.stringSetting(
title,
neededAtPhase,
prefix,
init
) as ReadOnlyProperty<Any, TemplateSetting<String, StringSettingType>>
@@ -182,11 +187,13 @@ abstract class Template : SettingsOwner, EntitiesOwnerDescriptor, DisplayableSet
final override fun booleanSetting(
title: String,
neededAtPhase: GenerationPhase,
prefix: String,
init: BooleanSettingType.Builder.() -> Unit
): ReadOnlyProperty<Any, TemplateSetting<Boolean, BooleanSettingType>> =
super.booleanSetting(
title,
neededAtPhase,
prefix,
init
) as ReadOnlyProperty<Any, TemplateSetting<Boolean, BooleanSettingType>>
@@ -195,12 +202,14 @@ abstract class Template : SettingsOwner, EntitiesOwnerDescriptor, DisplayableSet
title: String,
neededAtPhase: GenerationPhase,
parser: Parser<V>,
prefix: String,
init: ValueSettingType.Builder<V>.() -> Unit
): ReadOnlyProperty<Any, TemplateSetting<V, ValueSettingType<V>>> =
super.valueSetting(
title,
neededAtPhase,
parser,
prefix,
init
) as ReadOnlyProperty<Any, TemplateSetting<V, ValueSettingType<V>>>
@@ -208,11 +217,13 @@ abstract class Template : SettingsOwner, EntitiesOwnerDescriptor, DisplayableSet
final override fun versionSetting(
title: String,
neededAtPhase: GenerationPhase,
prefix: String,
init: VersionSettingType.Builder.() -> Unit
): ReadOnlyProperty<Any, TemplateSetting<Version, VersionSettingType>> =
super.versionSetting(
title,
neededAtPhase,
prefix,
init
) as ReadOnlyProperty<Any, TemplateSetting<Version, VersionSettingType>>
@@ -221,12 +232,14 @@ abstract class Template : SettingsOwner, EntitiesOwnerDescriptor, DisplayableSet
title: String,
neededAtPhase: GenerationPhase,
parser: Parser<V>,
prefix: String,
init: ListSettingType.Builder<V>.() -> Unit
): ReadOnlyProperty<Any, TemplateSetting<List<V>, ListSettingType<V>>> =
super.listSetting(
title,
neededAtPhase,
parser,
prefix,
init
) as ReadOnlyProperty<Any, TemplateSetting<List<V>, ListSettingType<V>>>
@@ -235,11 +248,13 @@ abstract class Template : SettingsOwner, EntitiesOwnerDescriptor, DisplayableSet
final override fun pathSetting(
title: String,
neededAtPhase: GenerationPhase,
prefix: String,
init: PathSettingType.Builder.() -> Unit
): ReadOnlyProperty<Any, TemplateSetting<Path, PathSettingType>> =
super.pathSetting(
title,
neededAtPhase,
prefix,
init
) as ReadOnlyProperty<Any, TemplateSetting<Path, PathSettingType>>
@@ -247,9 +262,10 @@ abstract class Template : SettingsOwner, EntitiesOwnerDescriptor, DisplayableSet
inline fun <reified E> enumSetting(
title: String,
neededAtPhase: GenerationPhase,
prefix: String = "",
crossinline init: DropDownSettingType.Builder<E>.() -> Unit = {}
): ReadOnlyProperty<Any, TemplateSetting<E, DropDownSettingType<E>>> where E : Enum<E>, E : DisplayableSettingItem =
enumSettingImpl(title, neededAtPhase, init) as ReadOnlyProperty<Any, TemplateSetting<E, DropDownSettingType<E>>>
enumSettingImpl(title, neededAtPhase, prefix, init) as ReadOnlyProperty<Any, TemplateSetting<E, DropDownSettingType<E>>>
companion object {
fun parser(templateId: Identificator): Parser<Template> = mapParser { map, path ->
@@ -23,7 +23,7 @@ abstract class Wizard(createPlugins: PluginsCreator, servicesManager: ServicesMa
private fun initNonPluginDefaultValues() {
context.writeSettings {
KotlinPlugin::modules.reference.notRequiredSettingValue
KotlinPlugin.modules.notRequiredSettingValue
?.withAllSubModules(includeSourcesets = true)
?.forEach { module ->
with(module) { initDefaultValuesForSettings() }
@@ -41,7 +41,7 @@ abstract class Wizard(createPlugins: PluginsCreator, servicesManager: ServicesMa
fun validate(phases: Set<GenerationPhase>): ValidationResult = context.read {
pluginSettings.map { setting ->
val value = setting.reference.notRequiredSettingValue ?: return@map ValidationResult.OK
val value = setting.notRequiredSettingValue ?: return@map ValidationResult.OK
if (setting.validateOnProjectCreation && setting.neededAtPhase in phases && setting.isActive(this))
(setting.validator as SettingValidator<Any>).validate(this, value)
else ValidationResult.OK
@@ -56,7 +56,7 @@ abstract class Wizard(createPlugins: PluginsCreator, servicesManager: ServicesMa
val serializer = setting.type.serializer as? SettingSerializer.Serializer<Any> ?: continue
service<SettingSavingWizardService>().saveSettingValue(
setting.path,
serializer.toString(setting.reference.settingValue)
serializer.toString(setting.settingValue)
)
}
}