mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-07 05:09:37 +07:00
project configuration dsl: state reader
GitOrigin-RevId: d477fde05a6722e60c277ee53eced3cea6b41772
This commit is contained in:
committed by
intellij-monorepo-bot
parent
3590278d34
commit
bb260c8522
@@ -1,18 +1,15 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.configurationStore
|
||||
|
||||
import com.intellij.openapi.components.PersistentStateComponentWithModificationTracker
|
||||
import com.intellij.openapi.components.RoamingType
|
||||
import com.intellij.openapi.components.State
|
||||
import com.intellij.openapi.components.Storage
|
||||
import com.intellij.openapi.components.*
|
||||
import com.intellij.openapi.util.ModificationTracker
|
||||
import com.intellij.util.ThreeState
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
internal fun createComponentInfo(component: Any, stateSpec: State?): ComponentInfo {
|
||||
internal fun createComponentInfo(component: Any, stateSpec: State?, serviceDescriptor: ServiceDescriptor?): ComponentInfo {
|
||||
return when (component) {
|
||||
is ModificationTracker -> ComponentWithModificationTrackerInfo(component, stateSpec)
|
||||
is PersistentStateComponentWithModificationTracker<*> -> ComponentWithStateModificationTrackerInfo(component, stateSpec!!)
|
||||
is ModificationTracker -> ComponentWithModificationTrackerInfo(component, stateSpec, serviceDescriptor?.configurationSchemaKey)
|
||||
is PersistentStateComponentWithModificationTracker<*> -> ComponentWithStateModificationTrackerInfo(component, stateSpec!!, serviceDescriptor?.configurationSchemaKey)
|
||||
else -> {
|
||||
val componentInfo = ComponentInfoImpl(component, stateSpec)
|
||||
if (stateSpec != null && !stateSpec.storages.isEmpty() && stateSpec.storages.all(::isUseSaveThreshold)) {
|
||||
@@ -27,7 +24,10 @@ private fun isUseSaveThreshold(storage: Storage): Boolean {
|
||||
return storage.useSaveThreshold != ThreeState.NO && getEffectiveRoamingType(storage.roamingType, storage.path) === RoamingType.DISABLED
|
||||
}
|
||||
|
||||
internal abstract class ComponentInfo {
|
||||
abstract class ComponentInfo {
|
||||
open val configurationSchemaKey: String?
|
||||
get() = null
|
||||
|
||||
abstract val component: Any
|
||||
abstract val stateSpec: State?
|
||||
|
||||
@@ -38,6 +38,8 @@ internal abstract class ComponentInfo {
|
||||
|
||||
var lastSaved: Int = -1
|
||||
|
||||
var affectedPropertyNames: List<String> = emptyList()
|
||||
|
||||
open fun updateModificationCount(newCount: Long = currentModificationCount) {
|
||||
}
|
||||
}
|
||||
@@ -63,7 +65,8 @@ private abstract class ModificationTrackerAwareComponentInfo : ComponentInfo() {
|
||||
}
|
||||
|
||||
private class ComponentWithStateModificationTrackerInfo(override val component: PersistentStateComponentWithModificationTracker<*>,
|
||||
override val stateSpec: State) : ModificationTrackerAwareComponentInfo() {
|
||||
override val stateSpec: State,
|
||||
override val configurationSchemaKey: String?) : ModificationTrackerAwareComponentInfo() {
|
||||
override val currentModificationCount: Long
|
||||
get() = component.stateModificationCount
|
||||
|
||||
@@ -71,7 +74,8 @@ private class ComponentWithStateModificationTrackerInfo(override val component:
|
||||
}
|
||||
|
||||
private class ComponentWithModificationTrackerInfo(override val component: ModificationTracker,
|
||||
override val stateSpec: State?) : ModificationTrackerAwareComponentInfo() {
|
||||
override val stateSpec: State?,
|
||||
override val configurationSchemaKey: String?) : ModificationTrackerAwareComponentInfo() {
|
||||
override val currentModificationCount: Long
|
||||
get() = component.modificationCount
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.jdom.Element
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.annotations.CalledInAwt
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import java.io.IOException
|
||||
@@ -74,10 +75,11 @@ internal fun setRoamableComponentSaveThreshold(thresholdInSeconds: Int) {
|
||||
NOT_ROAMABLE_COMPONENT_SAVE_THRESHOLD = thresholdInSeconds
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
abstract class ComponentStoreImpl : IComponentStore {
|
||||
private val components = Collections.synchronizedMap(THashMap<String, ComponentInfo>())
|
||||
|
||||
internal open val project: Project?
|
||||
open val project: Project?
|
||||
get() = null
|
||||
|
||||
open val loadPolicy: StateLoadPolicy
|
||||
@@ -87,12 +89,12 @@ abstract class ComponentStoreImpl : IComponentStore {
|
||||
|
||||
internal fun getComponents(): Map<String, ComponentInfo> = components
|
||||
|
||||
override fun initComponent(component: Any, isService: Boolean) {
|
||||
override fun initComponent(component: Any, serviceDescriptor: ServiceDescriptor?) {
|
||||
var componentName = ""
|
||||
try {
|
||||
@Suppress("DEPRECATION")
|
||||
if (component is PersistentStateComponent<*>) {
|
||||
componentName = initPersistenceStateComponent(component, getStateSpec(component), isService)
|
||||
componentName = initPersistenceStateComponent(component, getStateSpec(component), serviceDescriptor)
|
||||
}
|
||||
else if (component is com.intellij.openapi.util.JDOMExternalizable) {
|
||||
componentName = ComponentManagerImpl.getComponentName(component)
|
||||
@@ -110,13 +112,13 @@ abstract class ComponentStoreImpl : IComponentStore {
|
||||
override fun initPersistencePlainComponent(component: Any, key: String) {
|
||||
initPersistenceStateComponent(PersistenceStateAdapter(component),
|
||||
StateAnnotation(key, FileStorageAnnotation(StoragePathMacros.WORKSPACE_FILE, false)),
|
||||
isService = false)
|
||||
serviceDescriptor = null)
|
||||
}
|
||||
|
||||
private fun initPersistenceStateComponent(component: PersistentStateComponent<*>, stateSpec: State, isService: Boolean): String {
|
||||
private fun initPersistenceStateComponent(component: PersistentStateComponent<*>, stateSpec: State, serviceDescriptor: ServiceDescriptor?): String {
|
||||
val componentName = stateSpec.name
|
||||
val info = doAddComponent(componentName, component, stateSpec)
|
||||
if (initComponent(info, null, ThreeState.NO) && isService) {
|
||||
val info = doAddComponent(componentName, component, stateSpec, serviceDescriptor)
|
||||
if (initComponent(info, null, ThreeState.NO) && serviceDescriptor != null) {
|
||||
// if not service, so, component manager will check it later for all components
|
||||
project?.let {
|
||||
val app = ApplicationManager.getApplication()
|
||||
@@ -170,6 +172,7 @@ abstract class ComponentStoreImpl : IComponentStore {
|
||||
|
||||
// well, strictly speaking each component saving takes some time, but +/- several seconds doesn't matter
|
||||
val nowInSeconds = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()).toInt()
|
||||
val isSaveModLogEnabled = SAVE_MOD_LOG.isDebugEnabled && !ApplicationManager.getApplication().isUnitTestMode
|
||||
for (name in names) {
|
||||
val start = System.currentTimeMillis()
|
||||
try {
|
||||
@@ -191,7 +194,10 @@ abstract class ComponentStoreImpl : IComponentStore {
|
||||
info.lastSaved = nowInSeconds
|
||||
}
|
||||
else {
|
||||
SAVE_MOD_LOG.debug { "Skip $name: was already saved in last ${TimeUnit.SECONDS.toMinutes(NOT_ROAMABLE_COMPONENT_SAVE_THRESHOLD_DEFAULT.toLong())} minutes (lastSaved ${info.lastSaved}, now: $nowInSeconds)" }
|
||||
if (isSaveModLogEnabled) {
|
||||
SAVE_MOD_LOG.debug("Skip $name: was already saved in last ${TimeUnit.SECONDS.toMinutes(NOT_ROAMABLE_COMPONENT_SAVE_THRESHOLD_DEFAULT.toLong())} minutes" +
|
||||
" (lastSaved ${info.lastSaved}, now: $nowInSeconds)")
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
@@ -259,11 +265,15 @@ abstract class ComponentStoreImpl : IComponentStore {
|
||||
return
|
||||
}
|
||||
|
||||
val state = (component as PersistentStateComponent<*>).state ?: return
|
||||
var state: Any? = null
|
||||
// state can be null, so, we cannot compare to null to check is state was requested or not
|
||||
var stateRequested = false
|
||||
|
||||
val stateSpec = info.stateSpec!!
|
||||
val effectiveComponentName = componentName ?: stateSpec.name
|
||||
val stateStorageChooser = component as? StateStorageChooserEx
|
||||
val storageSpecs = getStorageSpecs(component, stateSpec, StateStorageOperation.WRITE)
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val storageSpecs = getStorageSpecs(component as PersistentStateComponent<Any>, stateSpec, StateStorageOperation.WRITE)
|
||||
for (storageSpec in storageSpecs) {
|
||||
@Suppress("IfThenToElvis")
|
||||
var resolution = if (stateStorageChooser == null) Resolution.DO else stateStorageChooser.getResolution(storageSpec, StateStorageOperation.WRITE)
|
||||
@@ -280,12 +290,28 @@ abstract class ComponentStoreImpl : IComponentStore {
|
||||
}
|
||||
}
|
||||
|
||||
session.getProducer(storage)?.setState(component, effectiveComponentName, if (storageSpec.deprecated || resolution == Resolution.CLEAR) null else state)
|
||||
val sessionProducer = session.getProducer(storage) ?: continue
|
||||
if (storageSpec.deprecated || resolution == Resolution.CLEAR) {
|
||||
sessionProducer.setState(component, effectiveComponentName, null)
|
||||
}
|
||||
else {
|
||||
if (!stateRequested) {
|
||||
stateRequested = true
|
||||
state = (info.component as PersistentStateComponent<*>).state
|
||||
}
|
||||
|
||||
setStateToSaveSessionProducer(state, info, effectiveComponentName, sessionProducer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// method is not called if storage is deprecated or clear was requested (state in these cases is null), but called if state is null if returned so from component
|
||||
protected open fun setStateToSaveSessionProducer(state: Any?, info: ComponentInfo, effectiveComponentName: String, sessionProducer: SaveSessionProducer) {
|
||||
sessionProducer.setState(info.component, effectiveComponentName, state)
|
||||
}
|
||||
|
||||
private fun initJdomExternalizable(@Suppress("DEPRECATION") component: com.intellij.openapi.util.JDOMExternalizable, componentName: String): String? {
|
||||
doAddComponent(componentName, component, null)
|
||||
doAddComponent(componentName, component, stateSpec = null, serviceDescriptor = null)
|
||||
|
||||
if (loadPolicy != StateLoadPolicy.LOAD) {
|
||||
return null
|
||||
@@ -312,8 +338,8 @@ abstract class ComponentStoreImpl : IComponentStore {
|
||||
return componentName
|
||||
}
|
||||
|
||||
private fun doAddComponent(name: String, component: Any, stateSpec: State?): ComponentInfo {
|
||||
val newInfo = createComponentInfo(component, stateSpec)
|
||||
private fun doAddComponent(name: String, component: Any, stateSpec: State?, serviceDescriptor: ServiceDescriptor?): ComponentInfo {
|
||||
val newInfo = createComponentInfo(component, stateSpec, serviceDescriptor)
|
||||
val existing = components.put(name, newInfo)
|
||||
if (existing != null && existing.component !== component) {
|
||||
components.put(name, existing)
|
||||
@@ -324,23 +350,21 @@ abstract class ComponentStoreImpl : IComponentStore {
|
||||
}
|
||||
|
||||
private fun initComponent(info: ComponentInfo, changedStorages: Set<StateStorage>?, reloadData: ThreeState): Boolean {
|
||||
if (loadPolicy == StateLoadPolicy.NOT_LOAD) {
|
||||
return false
|
||||
return when {
|
||||
loadPolicy == StateLoadPolicy.NOT_LOAD -> false
|
||||
doInitComponent(info, changedStorages, reloadData) -> {
|
||||
// if component was initialized, update lastModificationCount
|
||||
info.updateModificationCount()
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
if (doInitComponent(info.stateSpec!!, info.component as PersistentStateComponent<Any>, changedStorages, reloadData)) {
|
||||
// if component was initialized, update lastModificationCount
|
||||
info.updateModificationCount()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun doInitComponent(stateSpec: State,
|
||||
component: PersistentStateComponent<Any>,
|
||||
changedStorages: Set<StateStorage>?,
|
||||
reloadData: ThreeState): Boolean {
|
||||
private fun doInitComponent(info: ComponentInfo, changedStorages: Set<StateStorage>?, reloadData: ThreeState): Boolean {
|
||||
val stateSpec = info.stateSpec!!
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val component = info.component as PersistentStateComponent<Any>
|
||||
val name = stateSpec.name
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val stateClass: Class<Any> = when (component) {
|
||||
@@ -360,7 +384,11 @@ abstract class ComponentStoreImpl : IComponentStore {
|
||||
}
|
||||
|
||||
val storage = storageManager.getStateStorage(storageSpec)
|
||||
val stateGetter = doCreateStateGetter(reloadData, changedStorages, storage, stateSpec, name, component, stateClass)
|
||||
|
||||
// if storage marked as changed, it means that analyzeExternalChangesAndUpdateIfNeed was called for it and storage is already reloaded
|
||||
val isReloadDataForStorage = if (reloadData == ThreeState.UNSURE) changedStorages!!.contains(storage) else reloadData.toBoolean()
|
||||
|
||||
val stateGetter = doCreateStateGetter(isReloadDataForStorage, storage, info, name, stateClass)
|
||||
var state = stateGetter.getState(defaultState)
|
||||
if (state == null) {
|
||||
if (changedStorages != null && changedStorages.contains(storage)) {
|
||||
@@ -393,24 +421,21 @@ abstract class ComponentStoreImpl : IComponentStore {
|
||||
return true
|
||||
}
|
||||
|
||||
private fun doCreateStateGetter(reloadData: ThreeState,
|
||||
changedStorages: Set<StateStorage>?,
|
||||
storage: StateStorage,
|
||||
stateSpec: State,
|
||||
name: String,
|
||||
component: PersistentStateComponent<Any>,
|
||||
stateClass: Class<Any>): StateGetter<Any> {
|
||||
// if storage marked as changed, it means that analyzeExternalChangesAndUpdateIfNeed was called for it and storage is already reloaded
|
||||
val isReloadDataForStorage = if (reloadData == ThreeState.UNSURE) changedStorages!!.contains(storage) else reloadData.toBoolean()
|
||||
|
||||
protected open fun doCreateStateGetter(reloadData: Boolean,
|
||||
storage: StateStorage,
|
||||
info: ComponentInfo,
|
||||
name: String,
|
||||
stateClass: Class<Any>): StateGetter<Any> {
|
||||
// use.loaded.state.as.existing used in upsource
|
||||
val isUseLoadedStateAsExisting = stateSpec.useLoadedStateAsExisting
|
||||
&& isUseLoadedStateAsExisting(storage)
|
||||
&& SystemProperties.getBooleanProperty("use.loaded.state.as.existing", true)
|
||||
return createStateGetter(isUseLoadedStateAsExisting, storage, component, name, stateClass, reloadData = isReloadDataForStorage)
|
||||
val isUseLoadedStateAsExisting = info.stateSpec!!.useLoadedStateAsExisting && isUseLoadedStateAsExisting(storage)
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return createStateGetter(isUseLoadedStateAsExisting, storage, info.component as PersistentStateComponent<Any>, name, stateClass, reloadData)
|
||||
}
|
||||
|
||||
protected open fun isUseLoadedStateAsExisting(storage: StateStorage) = (storage as? XmlElementStorage)?.roamingType != RoamingType.DISABLED
|
||||
protected open fun isUseLoadedStateAsExisting(storage: StateStorage): Boolean {
|
||||
return (storage as? XmlElementStorage)?.roamingType != RoamingType.DISABLED
|
||||
&& SystemProperties.getBooleanProperty("use.loaded.state.as.existing", true)
|
||||
}
|
||||
|
||||
protected open fun getPathMacroManagerForDefaults(): PathMacroManager? = null
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.configurationStore
|
||||
|
||||
import com.intellij.openapi.components.ServiceDescriptor
|
||||
import com.intellij.openapi.components.SettingsSavingComponent
|
||||
import com.intellij.openapi.diagnostic.runAndLogException
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
@@ -36,7 +37,7 @@ abstract class ComponentStoreWithExtraComponents : ComponentStoreImpl() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun initComponent(component: Any, isService: Boolean) {
|
||||
override fun initComponent(component: Any, serviceDescriptor: ServiceDescriptor?) {
|
||||
@Suppress("DEPRECATION")
|
||||
if (component is com.intellij.configurationStore.SettingsSavingComponent) {
|
||||
asyncSettingsSavingComponents.add(component)
|
||||
@@ -45,7 +46,7 @@ abstract class ComponentStoreWithExtraComponents : ComponentStoreImpl() {
|
||||
settingsSavingComponents.add(component)
|
||||
}
|
||||
|
||||
super.initComponent(component, isService)
|
||||
super.initComponent(component, serviceDescriptor)
|
||||
}
|
||||
|
||||
internal suspend fun saveSettingsSavingComponentsAndCommitComponents(result: SaveResult, forceSavingAllSettings: Boolean): SaveSessionProducerManager {
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.intellij.util.io.*
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.annotations.CalledInAny
|
||||
import java.nio.file.AccessDeniedException
|
||||
import java.nio.file.Path
|
||||
@@ -32,7 +33,8 @@ import java.nio.file.Paths
|
||||
internal val IProjectStore.nameFile: Path
|
||||
get() = Paths.get(directoryStorePath, ProjectImpl.NAME_FILE)
|
||||
|
||||
private open class ProjectStoreImpl(project: Project) : ProjectStoreBase(project) {
|
||||
@ApiStatus.Internal
|
||||
open class ProjectStoreImpl(project: Project) : ProjectStoreBase(project) {
|
||||
private var lastSavedProjectName: String? = null
|
||||
|
||||
init {
|
||||
@@ -145,7 +147,8 @@ private open class ProjectStoreImpl(project: Project) : ProjectStoreBase(project
|
||||
}
|
||||
}
|
||||
|
||||
private class ProjectWithModulesStoreImpl(project: Project) : ProjectStoreImpl(project) {
|
||||
@ApiStatus.Internal
|
||||
open class ProjectWithModulesStoreImpl(project: Project) : ProjectStoreImpl(project) {
|
||||
override suspend fun saveModules(errors: MutableList<Throwable>, isForceSavingAllSettings: Boolean): List<SaveSession> {
|
||||
val modules = ModuleManager.getInstance(project)?.modules ?: Module.EMPTY_ARRAY
|
||||
if (modules.isEmpty()) {
|
||||
|
||||
@@ -31,7 +31,7 @@ abstract class SaveSessionBase : SaveSessionProducer, SafeWriteRequestor, LargeF
|
||||
setSerializedState(componentName, element)
|
||||
}
|
||||
|
||||
protected abstract fun setSerializedState(componentName: String, element: Element?)
|
||||
abstract fun setSerializedState(componentName: String, element: Element?)
|
||||
}
|
||||
|
||||
internal fun serializeState(state: Any): Element? {
|
||||
|
||||
@@ -9,6 +9,7 @@ import com.intellij.openapi.progress.ProcessCanceledException
|
||||
import com.intellij.openapi.util.JDOMUtil
|
||||
import com.intellij.util.isEmpty
|
||||
import org.jdom.Element
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
abstract class StorageBaseEx<T : Any> : StateStorageBase<T>() {
|
||||
internal fun <S : Any> createGetSession(component: PersistentStateComponent<S>, componentName: String, stateClass: Class<S>, reload: Boolean = false): StateGetter<S> {
|
||||
@@ -31,13 +32,12 @@ internal fun <S : Any> createStateGetter(isUseLoadedStateAsExisting: Boolean, st
|
||||
return storage.getState(component, componentName, stateClass, mergeInto, reloadData)
|
||||
}
|
||||
|
||||
override fun archiveState() : S? {
|
||||
return null
|
||||
}
|
||||
override fun archiveState(): S? = null
|
||||
}
|
||||
}
|
||||
|
||||
internal interface StateGetter<S : Any> {
|
||||
@ApiStatus.Internal
|
||||
interface StateGetter<S : Any> {
|
||||
fun getState(mergeInto: S? = null): S?
|
||||
|
||||
fun archiveState(): S?
|
||||
|
||||
@@ -68,7 +68,7 @@ internal class ApplicationStoreTest {
|
||||
componentStore.storageManager.removeStreamProvider(MyStreamProvider::class.java)
|
||||
componentStore.storageManager.addStreamProvider(streamProvider)
|
||||
|
||||
componentStore.initComponent(component, false)
|
||||
componentStore.initComponent(component, null)
|
||||
component.foo = "newValue"
|
||||
componentStore.save()
|
||||
|
||||
@@ -87,7 +87,7 @@ internal class ApplicationStoreTest {
|
||||
val storageManager = componentStore.storageManager
|
||||
storageManager.removeStreamProvider(MyStreamProvider::class.java)
|
||||
storageManager.addStreamProvider(streamProvider)
|
||||
componentStore.initComponent(component, false)
|
||||
componentStore.initComponent(component, null)
|
||||
assertThat(component.foo).isEqualTo("newValue")
|
||||
|
||||
assertThat(Paths.get(storageManager.expandMacros(fileSpec))).doesNotExist()
|
||||
@@ -116,7 +116,7 @@ internal class ApplicationStoreTest {
|
||||
|
||||
testAppConfig.refreshVfs()
|
||||
|
||||
componentStore.initComponent(component, false)
|
||||
componentStore.initComponent(component, null)
|
||||
assertThat(component.foo).isEqualTo("new")
|
||||
|
||||
component.foo = "new2"
|
||||
@@ -152,7 +152,7 @@ internal class ApplicationStoreTest {
|
||||
testAppConfig.refreshVfs()
|
||||
|
||||
val component = A()
|
||||
componentStore.initComponent(component, false)
|
||||
componentStore.initComponent(component, null)
|
||||
|
||||
component.options.foo = "new"
|
||||
|
||||
@@ -203,7 +203,7 @@ internal class ApplicationStoreTest {
|
||||
testAppConfig.refreshVfs()
|
||||
|
||||
val component = SeveralStoragesConfigured()
|
||||
componentStore.initComponent(component, false)
|
||||
componentStore.initComponent(component, null)
|
||||
assertThat(component.foo).isEqualTo("new")
|
||||
|
||||
componentStore.save()
|
||||
@@ -221,7 +221,7 @@ internal class ApplicationStoreTest {
|
||||
testAppConfig.refreshVfs()
|
||||
|
||||
val component = A()
|
||||
componentStore.initComponent(component, false)
|
||||
componentStore.initComponent(component, null)
|
||||
assertThat(component.options).isEqualTo(TestState("old"))
|
||||
|
||||
componentStore.save()
|
||||
@@ -247,12 +247,12 @@ internal class ApplicationStoreTest {
|
||||
val component = A()
|
||||
component.isThrowErrorOnLoadState = true
|
||||
assertThatThrownBy {
|
||||
componentStore.initComponent(component, false)
|
||||
componentStore.initComponent(component, null)
|
||||
}.isInstanceOf(ProcessCanceledException::class.java)
|
||||
assertThat(component.options).isEqualTo(TestState())
|
||||
|
||||
component.isThrowErrorOnLoadState = false
|
||||
componentStore.initComponent(component, false)
|
||||
componentStore.initComponent(component, null)
|
||||
assertThat(component.options).isEqualTo(TestState("old"))
|
||||
}
|
||||
|
||||
@@ -266,7 +266,7 @@ internal class ApplicationStoreTest {
|
||||
testAppConfig.refreshVfs()
|
||||
|
||||
val component = AWorkspace()
|
||||
componentStore.initComponent(component, false)
|
||||
componentStore.initComponent(component, null)
|
||||
assertThat(component.options).isEqualTo(TestState("old"))
|
||||
|
||||
try {
|
||||
@@ -289,7 +289,7 @@ internal class ApplicationStoreTest {
|
||||
class AOther : A()
|
||||
|
||||
val component = AOther()
|
||||
componentStore.initComponent(component, false)
|
||||
componentStore.initComponent(component, null)
|
||||
component.options.foo = "old"
|
||||
|
||||
componentStore.save()
|
||||
@@ -312,15 +312,15 @@ internal class ApplicationStoreTest {
|
||||
class COther : A()
|
||||
|
||||
val component = AOther()
|
||||
componentStore.initComponent(component, false)
|
||||
componentStore.initComponent(component, null)
|
||||
component.options.foo = "old"
|
||||
|
||||
val component2 = BOther()
|
||||
componentStore.initComponent(component2, false)
|
||||
componentStore.initComponent(component2, null)
|
||||
component2.options.foo = "old?"
|
||||
|
||||
val component3 = COther()
|
||||
componentStore.initComponent(component3, false)
|
||||
componentStore.initComponent(component3, null)
|
||||
component3.options.bar = "foo"
|
||||
|
||||
componentStore.save()
|
||||
|
||||
@@ -61,7 +61,7 @@ internal class ComponentStoreModificationTrackerTest {
|
||||
}
|
||||
|
||||
val component = A()
|
||||
componentStore.initComponent(component, false)
|
||||
componentStore.initComponent(component, null)
|
||||
|
||||
assertThat(component.modificationCount).isEqualTo(0)
|
||||
assertThat(component.stateCalledCount.get()).isEqualTo(0)
|
||||
@@ -128,7 +128,7 @@ internal class ComponentStoreModificationTrackerTest {
|
||||
}
|
||||
|
||||
val component = A()
|
||||
componentStore.initComponent(component, false)
|
||||
componentStore.initComponent(component, null)
|
||||
|
||||
assertThat(component.modificationCount.get()).isEqualTo(0)
|
||||
assertThat(component.stateCalledCount.get()).isEqualTo(0)
|
||||
|
||||
@@ -84,12 +84,12 @@ internal class DefaultProjectStoreTest {
|
||||
<main name="$TEST_COMPONENT_NAME"/><sub name="foo" /><sub name="bar" />
|
||||
</component>""".trimIndent()))
|
||||
val stateStore = ProjectManager.getInstance().defaultProject.stateStore as ComponentStoreImpl
|
||||
stateStore.initComponent(defaultTestComponent, true)
|
||||
stateStore.initComponent(defaultTestComponent, null)
|
||||
try {
|
||||
// obviously, project must be directory-based also
|
||||
createProjectAndUseInLoadComponentStateMode(tempDirManager, directoryBased = true) {
|
||||
val component = TestComponent()
|
||||
it.stateStore.initComponent(component, true)
|
||||
it.stateStore.initComponent(component, null)
|
||||
assertThat(component.state).isEqualTo(defaultTestComponent.state)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,7 +202,7 @@ internal class ProjectStoreTest {
|
||||
class AOther : A()
|
||||
|
||||
val component = AOther()
|
||||
componentStore.initComponent(component, false)
|
||||
componentStore.initComponent(component, null)
|
||||
assertThat(component.options.foo).isEqualTo("some data")
|
||||
|
||||
componentStore.save()
|
||||
@@ -237,7 +237,7 @@ internal class ProjectStoreTest {
|
||||
|
||||
private suspend fun test(project: Project): TestComponent {
|
||||
val testComponent = TestComponent()
|
||||
project.stateStore.initComponent(testComponent, true)
|
||||
project.stateStore.initComponent(testComponent, null)
|
||||
assertThat(testComponent.state).isEqualTo(TestState("customValue"))
|
||||
|
||||
testComponent.state!!.value = "foo"
|
||||
|
||||
@@ -1,26 +1,15 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.openapi.components.ex;
|
||||
|
||||
import com.intellij.openapi.components.ComponentManager;
|
||||
import com.intellij.openapi.components.ServiceDescriptor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
*/
|
||||
public interface ComponentManagerEx extends ComponentManager {
|
||||
void initializeComponent(@NotNull Object component, boolean service);
|
||||
default void initializeComponent(@NotNull Object component, @Nullable ServiceDescriptor serviceDescriptor) {
|
||||
}
|
||||
}
|
||||
@@ -216,10 +216,6 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements
|
||||
return ProgressManager.getInstance().getProgressIndicator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeComponent(@NotNull Object component, boolean service) {
|
||||
}
|
||||
|
||||
protected void handleInitComponentError(@NotNull Throwable ex, String componentClassName, PluginId pluginId) {
|
||||
LOG.error(ex);
|
||||
}
|
||||
@@ -511,7 +507,7 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements
|
||||
indicator.checkCanceled();
|
||||
setProgressDuringInit(indicator);
|
||||
}
|
||||
initializeComponent(instance, false);
|
||||
initializeComponent(instance, null);
|
||||
if (instance instanceof BaseComponent) {
|
||||
((BaseComponent)instance).initComponent();
|
||||
}
|
||||
|
||||
@@ -39,9 +39,9 @@ public abstract class PlatformComponentManagerImpl extends ComponentManagerImpl
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeComponent(@NotNull Object component, boolean service) {
|
||||
if (!service || !(component instanceof PathMacroManager || component instanceof IComponentStore)) {
|
||||
getComponentStore().initComponent(component, service);
|
||||
public void initializeComponent(@NotNull Object component, @Nullable ServiceDescriptor serviceDescriptor) {
|
||||
if (serviceDescriptor == null || !(component instanceof PathMacroManager || component instanceof IComponentStore)) {
|
||||
getComponentStore().initComponent(component, serviceDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -244,7 +244,7 @@ public final class ServiceManagerImpl implements Disposable {
|
||||
Disposer.register(myComponentManager, (Disposable)instance);
|
||||
}
|
||||
|
||||
myComponentManager.initializeComponent(instance, true);
|
||||
myComponentManager.initializeComponent(instance, myDescriptor);
|
||||
ParallelActivity.SERVICE.record(startTime, instance.getClass(), DefaultPicoContainer.getActivityLevel(container));
|
||||
return instance;
|
||||
}
|
||||
|
||||
@@ -44,18 +44,20 @@ internal class KotlinAwareBeanBinding(beanClass: Class<*>, accessor: MutableAcce
|
||||
}
|
||||
}
|
||||
|
||||
private fun serializeBaseStateInto(o: BaseState, _element: Element?, filter: SerializationFilter?): Element? {
|
||||
fun serializeBaseStateInto(o: BaseState, _element: Element?, filter: SerializationFilter?, excludedPropertyNames: Collection<String>? = null): Element? {
|
||||
var element = _element
|
||||
// order of bindings must be used, not order of properties
|
||||
var bindingIndices: IntArrayList? = null
|
||||
for (property in o.__getProperties()) {
|
||||
if (property.isEqualToDefault()) {
|
||||
val propertyName = property.name!!
|
||||
|
||||
if (property.isEqualToDefault() || (excludedPropertyNames != null && excludedPropertyNames.contains(propertyName))) {
|
||||
continue
|
||||
}
|
||||
|
||||
val propertyBindingIndex = findBindingIndex(property.name!!)
|
||||
val propertyBindingIndex = findBindingIndex(propertyName)
|
||||
if (propertyBindingIndex < 0) {
|
||||
logger<BaseState>().debug("cannot find binding for property ${property.name}")
|
||||
logger<BaseState>().debug("cannot find binding for property ${propertyName}")
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
@@ -61,6 +61,11 @@ fun <T : Any> T.serialize(filter: SerializationFilter? = getDefaultSerialization
|
||||
}
|
||||
}
|
||||
|
||||
fun deserializeBaseStateWithCustomNameFilter(state: BaseState, excludedPropertyNames: Collection<String>): Element? {
|
||||
val binding = serializer.getClassBinding(state.javaClass) as KotlinAwareBeanBinding
|
||||
return binding.serializeBaseStateInto(state, null, getDefaultSerializationFilter(), excludedPropertyNames)
|
||||
}
|
||||
|
||||
inline fun <reified T: Any> Element.deserialize(): T = deserialize(T::class.java)
|
||||
|
||||
fun <T> Element.deserialize(clazz: Class<T>): T {
|
||||
|
||||
@@ -4,6 +4,7 @@ package com.intellij.openapi.components.impl.stores
|
||||
import com.intellij.configurationStore.SaveSession
|
||||
import com.intellij.configurationStore.StateStorageManager
|
||||
import com.intellij.openapi.components.PersistentStateComponent
|
||||
import com.intellij.openapi.components.ServiceDescriptor
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.util.messages.MessageBus
|
||||
import org.jetbrains.annotations.SystemIndependent
|
||||
@@ -14,7 +15,7 @@ interface IComponentStore {
|
||||
|
||||
fun setPath(path: @SystemIndependent String)
|
||||
|
||||
fun initComponent(component: Any, isService: Boolean)
|
||||
fun initComponent(component: Any, serviceDescriptor: ServiceDescriptor?)
|
||||
|
||||
fun initPersistencePlainComponent(component: Any, key: String)
|
||||
|
||||
|
||||
@@ -24,5 +24,6 @@
|
||||
<orderEntry type="module" module-name="intellij.java.testFramework" scope="TEST" />
|
||||
<orderEntry type="library" scope="TEST" name="gson" level="project" />
|
||||
<orderEntry type="module" module-name="intellij.yaml" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.configurationStore.impl" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -7,11 +7,6 @@
|
||||
]]>
|
||||
</description>
|
||||
|
||||
<!--<depends>org.jetbrains.kotlin</depends>-->
|
||||
|
||||
<!--<extensions defaultExtensionNs="org.jetbrains.kotlin">-->
|
||||
<!--<scriptDefinitionContributor implementation="com.intellij.configurationScript.ConfigurationScriptContributor" order="first"/>-->
|
||||
<!--</extensions>-->
|
||||
<extensions defaultExtensionNs="JavaScript.JsonSchema">
|
||||
<ProviderFactory implementation="com.intellij.configurationScript.IntellijConfigurationJsonSchemaProviderFactory"/>
|
||||
</extensions>
|
||||
@@ -20,5 +15,9 @@
|
||||
|
||||
<runConfigurationTemplateProvider implementation="com.intellij.configurationScript.providers.MyRunConfigurationTemplateProvider"/>
|
||||
<updateSettingsProvider implementation="com.intellij.configurationScript.providers.MyUpdateSettingsProvider"/>
|
||||
|
||||
<applicationService serviceInterface="com.intellij.openapi.project.impl.ProjectStoreFactory"
|
||||
serviceImplementation="com.intellij.configurationScript.providers.ConfigurationScriptProjectStoreFactory"
|
||||
overrides="true"/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.intellij.configurationScript
|
||||
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.openapi.vfs.VirtualFileManager
|
||||
@@ -11,6 +12,7 @@ import com.intellij.util.concurrency.SynchronizedClearableLazy
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import com.intellij.util.io.inputStreamIfExists
|
||||
import org.yaml.snakeyaml.nodes.MappingNode
|
||||
import org.yaml.snakeyaml.nodes.ScalarNode
|
||||
import org.yaml.snakeyaml.parser.ParserImpl
|
||||
import org.yaml.snakeyaml.reader.StreamReader
|
||||
import java.io.Reader
|
||||
@@ -38,6 +40,10 @@ internal class ConfigurationFileManager(project: Project) {
|
||||
registerClearableLazyValue(yamlData)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun getInstance(project: Project) = project.service<ConfigurationFileManager>()
|
||||
}
|
||||
|
||||
fun registerClearableLazyValue(value: SynchronizedClearableLazy<*>) {
|
||||
clearableLazyValues.add(value)
|
||||
}
|
||||
@@ -74,6 +80,27 @@ internal class ConfigurationFileManager(project: Project) {
|
||||
}
|
||||
|
||||
fun getConfigurationNode() = yamlData.value
|
||||
|
||||
fun findValueNode(namePath: String): MappingNode? {
|
||||
return findValueNodeByPath(namePath, yamlData.value ?: return null)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun findValueNodeByPath(namePath: String, rootNode: MappingNode): MappingNode? {
|
||||
var node = rootNode
|
||||
loop@
|
||||
for (name in namePath.splitToSequence('.')) {
|
||||
for (tuple in node.value) {
|
||||
val keyNode = tuple.keyNode
|
||||
if (keyNode is ScalarNode && keyNode.value == name) {
|
||||
node = tuple.valueNode as? MappingNode ?: continue
|
||||
continue@loop
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
return if (node === rootNode) null else node
|
||||
}
|
||||
|
||||
internal fun doRead(reader: Reader): MappingNode? {
|
||||
|
||||
@@ -4,11 +4,12 @@ import com.intellij.configurationStore.properties.CollectionStoredProperty
|
||||
import com.intellij.configurationStore.properties.MapStoredProperty
|
||||
import com.intellij.openapi.components.BaseState
|
||||
import com.intellij.openapi.components.ScalarProperty
|
||||
import com.intellij.openapi.components.StoredProperty
|
||||
import org.yaml.snakeyaml.nodes.MappingNode
|
||||
import org.yaml.snakeyaml.nodes.ScalarNode
|
||||
import org.yaml.snakeyaml.nodes.SequenceNode
|
||||
|
||||
internal fun readObject(instance: BaseState, node: MappingNode): BaseState {
|
||||
internal fun <T : BaseState> readIntoObject(instance: T, node: MappingNode, affectedPropertyConsumer: ((StoredProperty<Any>) -> Unit)? = null): T {
|
||||
val properties = instance.__getProperties()
|
||||
for (tuple in node.value) {
|
||||
val valueNode = tuple.valueNode
|
||||
@@ -17,6 +18,7 @@ internal fun readObject(instance: BaseState, node: MappingNode): BaseState {
|
||||
for (property in properties) {
|
||||
if (property is ScalarProperty && property.jsonType.isScalar && key == property.name) {
|
||||
property.parseAndSetValue(valueNode.value)
|
||||
affectedPropertyConsumer?.invoke(property)
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -25,6 +27,7 @@ internal fun readObject(instance: BaseState, node: MappingNode): BaseState {
|
||||
for (property in properties) {
|
||||
if (property is MapStoredProperty<*, *> && key == property.name) {
|
||||
readMap(property, valueNode)
|
||||
affectedPropertyConsumer?.invoke(property)
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -33,6 +36,7 @@ internal fun readObject(instance: BaseState, node: MappingNode): BaseState {
|
||||
for (property in properties) {
|
||||
if (property is CollectionStoredProperty<*, *> && key == property.name) {
|
||||
readCollection(property, valueNode)
|
||||
affectedPropertyConsumer?.invoke(property)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.intellij.configurationScript.providers
|
||||
|
||||
import com.intellij.configurationScript.ConfigurationFileManager
|
||||
import com.intellij.configurationScript.readIntoObject
|
||||
import com.intellij.configurationStore.*
|
||||
import com.intellij.openapi.components.BaseState
|
||||
import com.intellij.openapi.components.StateStorage
|
||||
import com.intellij.openapi.components.impl.stores.IComponentStore
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.project.impl.ProjectStoreFactory
|
||||
import com.intellij.util.ReflectionUtil
|
||||
import com.intellij.util.concurrency.SynchronizedClearableLazy
|
||||
import org.yaml.snakeyaml.nodes.MappingNode
|
||||
|
||||
internal class ConfigurationScriptProjectStoreFactory : ProjectStoreFactory {
|
||||
override fun createStore(project: Project): IComponentStore {
|
||||
return if (project.isDefault) DefaultProjectStoreImpl(project) else MyProjectStore(project)
|
||||
}
|
||||
}
|
||||
|
||||
private class MyProjectStore(project: Project) : ProjectWithModulesStoreImpl(project) {
|
||||
val data by lazy {
|
||||
val result = SynchronizedClearableLazy {
|
||||
val node = ConfigurationFileManager.getInstance(project).getConfigurationNode() ?: return@SynchronizedClearableLazy null
|
||||
readPluginsConfiguration(node)
|
||||
}
|
||||
ConfigurationFileManager.getInstance(project).registerClearableLazyValue(result)
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
override fun doCreateStateGetter(reloadData: Boolean,
|
||||
storage: StateStorage,
|
||||
info: ComponentInfo,
|
||||
name: String,
|
||||
stateClass: Class<Any>): StateGetter<Any> {
|
||||
val stateGetter = super.doCreateStateGetter(reloadData, storage, info, name, stateClass)
|
||||
val configurationSchemaKey = info.configurationSchemaKey ?: return stateGetter
|
||||
val node = ConfigurationFileManager.getInstance(project).findValueNode(configurationSchemaKey) ?: return stateGetter
|
||||
return object : StateGetter<Any> {
|
||||
override fun getState(mergeInto: Any?): Any? {
|
||||
var state = stateGetter.getState(mergeInto)
|
||||
if (state == null) {
|
||||
state = ReflectionUtil.newInstance(stateClass, false)
|
||||
}
|
||||
|
||||
val affectedProperties = mutableListOf<String>()
|
||||
readIntoObject(state as BaseState, node) { affectedProperties.add(it.name!!) }
|
||||
info.affectedPropertyNames = affectedProperties
|
||||
return state
|
||||
}
|
||||
|
||||
override fun archiveState(): Any? {
|
||||
// feature "preventing inappropriate state modification" is disabled for workspace components,
|
||||
// also, this feature makes little sense for properly implemented PersistenceStateComponent using BaseState
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// In general this method is not required in this form, because SaveSessionBase.setState accepts serialized state (Element) without any side-effects or performance degradation,
|
||||
// but it is better to express contract in code to make sure that it will be not broken in the future.
|
||||
override fun setStateToSaveSessionProducer(state: Any?, info: ComponentInfo, effectiveComponentName: String, sessionProducer: SaveSessionProducer) {
|
||||
val configurationSchemaKey = info.configurationSchemaKey
|
||||
if (state == null || configurationSchemaKey == null || info.affectedPropertyNames.isEmpty() || sessionProducer !is SaveSessionBase) {
|
||||
super.setStateToSaveSessionProducer(state, info, effectiveComponentName, sessionProducer)
|
||||
}
|
||||
else {
|
||||
val serializedState = deserializeBaseStateWithCustomNameFilter(state as BaseState, info.affectedPropertyNames)
|
||||
sessionProducer.setSerializedState(effectiveComponentName, serializedState)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun <T : BaseState> readComponentConfiguration(node: MappingNode, stateClass: Class<out T>): T? {
|
||||
return readIntoObject(ReflectionUtil.newInstance(stateClass), node)
|
||||
}
|
||||
@@ -2,7 +2,7 @@ package com.intellij.configurationScript.providers
|
||||
|
||||
import com.intellij.configurationScript.Keys
|
||||
import com.intellij.configurationScript.LOG
|
||||
import com.intellij.configurationScript.readObject
|
||||
import com.intellij.configurationScript.readIntoObject
|
||||
import com.intellij.configurationScript.schemaGenerators.processConfigurationTypes
|
||||
import com.intellij.configurationScript.schemaGenerators.rcFactoryIdToPropertyName
|
||||
import com.intellij.execution.configurations.ConfigurationFactory
|
||||
@@ -116,6 +116,6 @@ internal class RunConfigurationListReader(private val processor: (factory: Confi
|
||||
// very important - set BEFORE read to ensure that user can set any value for isAllowRunningInParallel and it will be not overridden by us later
|
||||
instance.isAllowRunningInParallel = factory.singletonPolicy.isAllowRunningInParallel
|
||||
}
|
||||
processor(factory, readObject(instance, node))
|
||||
processor(factory, readIntoObject(instance, node))
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,8 @@ package com.intellij.configurationScript.providers
|
||||
|
||||
import com.intellij.configurationScript.ConfigurationFileManager
|
||||
import com.intellij.configurationScript.Keys
|
||||
import com.intellij.configurationScript.readObject
|
||||
import com.intellij.configurationScript.readIntoObject
|
||||
import com.intellij.openapi.components.BaseState
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.project.processOpenedProjects
|
||||
import com.intellij.openapi.updateSettings.impl.UpdateSettingsProvider
|
||||
@@ -16,10 +15,10 @@ import org.yaml.snakeyaml.nodes.ScalarNode
|
||||
|
||||
private val dataKey = NotNullLazyKey.create<SynchronizedClearableLazy<PluginsConfiguration?>, Project>("MyUpdateSettingsProvider") { project ->
|
||||
val data = SynchronizedClearableLazy {
|
||||
val node = project.service<ConfigurationFileManager>().getConfigurationNode() ?: return@SynchronizedClearableLazy null
|
||||
val node = ConfigurationFileManager.getInstance(project).getConfigurationNode() ?: return@SynchronizedClearableLazy null
|
||||
readPluginsConfiguration(node)
|
||||
}
|
||||
project.service<ConfigurationFileManager>().registerClearableLazyValue(data)
|
||||
ConfigurationFileManager.getInstance(project).registerClearableLazyValue(data)
|
||||
data
|
||||
}
|
||||
|
||||
@@ -46,7 +45,7 @@ internal fun readPluginsConfiguration(rootNode: MappingNode): PluginsConfigurati
|
||||
val keyNode = tuple.keyNode
|
||||
if (keyNode is ScalarNode && keyNode.value == Keys.plugins) {
|
||||
val valueNode = tuple.valueNode as? MappingNode ?: continue
|
||||
return readObject(PluginsConfiguration(), valueNode) as PluginsConfiguration
|
||||
return readIntoObject(PluginsConfiguration(), valueNode)
|
||||
}
|
||||
}
|
||||
return null
|
||||
|
||||
40
plugins/configuration-script/test/ComponentStateTest.kt
Normal file
40
plugins/configuration-script/test/ComponentStateTest.kt
Normal file
@@ -0,0 +1,40 @@
|
||||
package com.intellij.configurationScript
|
||||
|
||||
import com.intellij.configurationScript.providers.readComponentConfiguration
|
||||
import com.intellij.openapi.components.BaseState
|
||||
import com.intellij.testFramework.ProjectRule
|
||||
import com.intellij.testFramework.assertions.Assertions.assertThat
|
||||
import org.intellij.lang.annotations.Language
|
||||
import org.junit.ClassRule
|
||||
import org.junit.Test
|
||||
|
||||
class ComponentStateTest {
|
||||
companion object {
|
||||
@JvmField
|
||||
@ClassRule
|
||||
val projectRule = ProjectRule()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun read() {
|
||||
val result = doReadComponentConfiguration("versionControl.git", """
|
||||
versionControl:
|
||||
git:
|
||||
updateMethod: rebase
|
||||
""")
|
||||
assertThat(result!!.updateMethod).isEqualTo(UpdateMethod.REBASE)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("SameParameterValue")
|
||||
private fun doReadComponentConfiguration(namePath: String, @Language("YAML") data: String): TestState? {
|
||||
return readComponentConfiguration(findValueNodeByPath(namePath, doRead(data.trimIndent().reader())!!)!!, TestState::class.java)
|
||||
}
|
||||
|
||||
private class TestState : BaseState() {
|
||||
var updateMethod by enum(UpdateMethod.BRANCH_DEFAULT)
|
||||
}
|
||||
|
||||
private enum class UpdateMethod {
|
||||
BRANCH_DEFAULT, MERGE, REBASE
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import org.junit.runners.Suite
|
||||
@RunWith(Suite::class)
|
||||
@Suite.SuiteClasses(
|
||||
ConfigurationFileTest::class,
|
||||
ComponentStateTest::class,
|
||||
ConfigurationSchemaTest::class,
|
||||
PropertyValueReaderTest::class
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user