IDEA-318843 storage tracker per project

GitOrigin-RevId: 8d045ad6b7fd94a8dedf3ddd84dca6a0b589bee1
This commit is contained in:
Vladimir Krivosheev
2023-04-25 18:34:06 +02:00
committed by intellij-monorepo-bot
parent 3e3c90d169
commit 3f3e985ff0
34 changed files with 445 additions and 479 deletions

View File

@@ -80,12 +80,12 @@ class ProjectInspectionManagerTest {
file.delete()
refreshProjectConfigDir(project)
StoreReloadManager.getInstance().reloadChangedStorageFiles()
StoreReloadManager.getInstance(project).reloadChangedStorageFiles()
assertThat(projectInspectionProfileManager.state).isEmpty()
file.write(doNotUseProjectProfileData)
refreshProjectConfigDir(project)
StoreReloadManager.getInstance().reloadChangedStorageFiles()
StoreReloadManager.getInstance(project).reloadChangedStorageFiles()
assertThat(projectInspectionProfileManager.state).isEqualTo(doNotUseProjectProfileState)
}
}
@@ -149,7 +149,7 @@ class ProjectInspectionManagerTest {
</component>""".trimIndent())
refreshProjectConfigDir(project)
StoreReloadManager.getInstance().reloadChangedStorageFiles()
StoreReloadManager.getInstance(project).reloadChangedStorageFiles()
assertThat(projectInspectionProfileManager.currentProfile.getToolDefaultState("Convert2Diamond", project).level).isEqualTo(
HighlightDisplayLevel.ERROR)
}
@@ -202,7 +202,7 @@ class ProjectInspectionManagerTest {
</component>""")
refreshProjectConfigDir(project)
StoreReloadManager.getInstance().reloadChangedStorageFiles()
StoreReloadManager.getInstance(project).reloadChangedStorageFiles()
assertThat(profileManager.currentProfile.isProjectLevel).isTrue()
assertThat(profileManager.currentProfile.name).isEqualTo("Project Default")
@@ -212,7 +212,7 @@ class ProjectInspectionManagerTest {
writeDefaultProfile(profileDir)
refreshProjectConfigDir(project)
StoreReloadManager.getInstance().reloadChangedStorageFiles()
StoreReloadManager.getInstance(project).reloadChangedStorageFiles()
assertThat(profileManager.currentProfile.name).isEqualTo("Project Default")

View File

@@ -4,17 +4,17 @@
package com.intellij.configurationStore
import com.intellij.openapi.Disposable
import com.intellij.openapi.application.Application
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.*
import com.intellij.openapi.components.StateStorageChooserEx.Resolution
import com.intellij.openapi.roots.ProjectModelElement
import com.intellij.openapi.util.Disposer
import com.intellij.openapi.util.io.FileUtilRt
import com.intellij.openapi.vfs.AsyncFileListener
import com.intellij.openapi.vfs.newvfs.events.VFileEvent
import com.intellij.util.ReflectionUtil
import com.intellij.util.SmartList
import com.intellij.util.ThreeState
import com.intellij.util.io.systemIndependentPath
import org.jdom.Element
import org.jetbrains.annotations.ApiStatus.Internal
import org.jetbrains.annotations.NonNls
@@ -24,6 +24,7 @@ import java.util.*
import java.util.concurrent.locks.ReentrantReadWriteLock
import kotlin.concurrent.read
import kotlin.concurrent.write
import kotlin.io.path.invariantSeparatorsPathString
/**
* If componentManager not specified, storage will not add file tracker
@@ -31,8 +32,9 @@ import kotlin.concurrent.write
@Internal
open class StateStorageManagerImpl(@NonNls private val rootTagName: String,
final override val macroSubstitutor: PathMacroSubstitutor? = null,
override val componentManager: ComponentManager?,
private val virtualFileTracker: StorageVirtualFileTracker? = createDefaultVirtualTracker(componentManager)) : StateStorageManager {
final override val componentManager: ComponentManager?) : StateStorageManager {
private val virtualFileTracker = createDefaultVirtualTracker(componentManager)
@Volatile
protected var macros: List<Macro> = Collections.emptyList()
@@ -55,37 +57,16 @@ open class StateStorageManagerImpl(@NonNls private val rootTagName: String,
}
// access under storageLock
@Suppress("LeakingThis")
private var isUseVfsListener = when (componentManager) {
null, is Application -> ThreeState.NO
null -> ThreeState.NO
else -> ThreeState.UNSURE // unsure because depends on stream provider state
}
open fun getFileBasedStorageConfiguration(fileSpec: String) = defaultFileBasedStorageConfiguration
open fun getFileBasedStorageConfiguration(fileSpec: String): FileBasedStorageConfiguration = defaultFileBasedStorageConfiguration
protected open val isUseXmlProlog: Boolean
get() = true
companion object {
private fun createDefaultVirtualTracker(componentManager: ComponentManager?): StorageVirtualFileTracker? {
return when (componentManager) {
null -> null
is Application -> StorageVirtualFileTracker(componentManager.messageBus)
else -> {
val tracker = (ApplicationManager.getApplication().stateStore.storageManager as? StateStorageManagerImpl)?.virtualFileTracker
?: return null
Disposer.register(componentManager, Disposable {
tracker.remove { it.storageManager.componentManager === componentManager }
})
tracker
}
}
}
}
@TestOnly
fun getVirtualFileTracker() = virtualFileTracker
/**
* Returns an old map.
*/
@@ -171,8 +152,8 @@ open class StateStorageManagerImpl(@NonNls private val rootTagName: String,
val storage = getCachedFileStorages(listOf(spec)).firstOrNull() ?: return
if (storage is StorageVirtualFileTracker.TrackedStorage) {
virtualFileTracker?.let { tracker ->
tracker.remove(storage.file.systemIndependentPath)
tracker.put(newPath.systemIndependentPath, storage)
tracker.remove(storage.file.invariantSeparatorsPathString)
tracker.put(newPath.invariantSeparatorsPathString, storage)
}
}
storage.setFile(null, newPath)
@@ -199,13 +180,12 @@ open class StateStorageManagerImpl(@NonNls private val rootTagName: String,
}
}
// overridden in upsource
protected open fun createStateStorage(storageClass: Class<out StateStorage>,
collapsedPath: String,
roamingType: RoamingType,
@Suppress("DEPRECATION", "removal") stateSplitter: Class<out StateSplitter>,
usePathMacroManager: Boolean,
exclusive: Boolean = false): StateStorage {
private fun createStateStorage(storageClass: Class<out StateStorage>,
collapsedPath: String,
roamingType: RoamingType,
@Suppress("DEPRECATION", "removal") stateSplitter: Class<out StateSplitter>,
usePathMacroManager: Boolean,
exclusive: Boolean = false): StateStorage {
if (storageClass != StateStorage::class.java) {
val constructor = storageClass.constructors.first { it.parameterCount <= 3 }
constructor.isAccessible = true
@@ -227,7 +207,7 @@ open class StateStorageManagerImpl(@NonNls private val rootTagName: String,
if (stateSplitter != StateSplitter::class.java && stateSplitter != StateSplitterEx::class.java) {
val storage = createDirectoryBasedStorage(filePath, collapsedPath, ReflectionUtil.newInstance(stateSplitter))
if (storage is StorageVirtualFileTracker.TrackedStorage) {
virtualFileTracker?.put(filePath.systemIndependentPath, storage)
virtualFileTracker?.put(filePath.invariantSeparatorsPathString, storage)
}
return storage
}
@@ -243,12 +223,11 @@ open class StateStorageManagerImpl(@NonNls private val rootTagName: String,
usePathMacroManager = usePathMacroManager,
rootTagName = if (exclusive) null else rootTagName)
if (isUseVfsListener == ThreeState.YES && storage is StorageVirtualFileTracker.TrackedStorage) {
virtualFileTracker?.put(filePath.systemIndependentPath, storage)
virtualFileTracker?.put(filePath.invariantSeparatorsPathString, storage)
}
return storage
}
// open for upsource
protected open fun createFileBasedStorage(path: Path,
collapsedPath: String,
roamingType: RoamingType,
@@ -353,9 +332,9 @@ open class StateStorageManagerImpl(@NonNls private val rootTagName: String,
}
}
protected open fun clearVirtualFileTracker(virtualFileTracker: StorageVirtualFileTracker) {
internal open fun clearVirtualFileTracker(virtualFileTracker: StorageVirtualFileTracker) {
for (collapsedPath in storages.keys) {
virtualFileTracker.remove(expandMacro(collapsedPath).systemIndependentPath)
virtualFileTracker.remove(expandMacro(collapsedPath).invariantSeparatorsPathString)
}
}
@@ -365,7 +344,7 @@ open class StateStorageManagerImpl(@NonNls private val rootTagName: String,
return value
}
if (collapsedPath.length > (key.length + 2) && collapsedPath[key.length] == '/' && collapsedPath.startsWith(key)) {
if (collapsedPath.length > (key.length + 2) && collapsedPath.get(key.length) == '/' && collapsedPath.startsWith(key)) {
return value.resolve(collapsedPath.substring(key.length + 1))
}
}
@@ -376,7 +355,7 @@ open class StateStorageManagerImpl(@NonNls private val rootTagName: String,
fun collapseMacro(path: String): String {
for ((key, value) in macros) {
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
val result = (path as java.lang.String).replace(value.systemIndependentPath, key)
val result = (path as java.lang.String).replace(value.invariantSeparatorsPathString, key)
if (result !== path) {
return result
}
@@ -399,7 +378,10 @@ internal val Storage.path: String
get() = value.ifEmpty { file }
internal fun getEffectiveRoamingType(roamingType: RoamingType, collapsedPath: String): RoamingType {
if (roamingType != RoamingType.DISABLED && (collapsedPath == StoragePathMacros.WORKSPACE_FILE || collapsedPath == StoragePathMacros.NON_ROAMABLE_FILE || isSpecialStorage(collapsedPath))) {
if (roamingType != RoamingType.DISABLED &&
(collapsedPath == StoragePathMacros.WORKSPACE_FILE ||
collapsedPath == StoragePathMacros.NON_ROAMABLE_FILE ||
isSpecialStorage(collapsedPath))) {
return RoamingType.DISABLED
}
else {
@@ -408,4 +390,38 @@ internal fun getEffectiveRoamingType(roamingType: RoamingType, collapsedPath: St
}
@Internal
data class Macro(@JvmField val key: String, @JvmField var value: Path)
data class Macro(@JvmField val key: String, @JvmField var value: Path)
@TestOnly
fun checkStorageIsNotTracked(module: ComponentManager) {
service<StorageVirtualFileTrackerHolder>().tracker.remove {
if (it.storageManager.componentManager === module) {
throw AssertionError("Storage manager is not disposed, module $module, storage $it")
}
false
}
}
@Service(Service.Level.APP)
private class StorageVirtualFileTrackerHolder {
@JvmField
val tracker = StorageVirtualFileTracker()
}
private class MyAsyncVfsListener : AsyncFileListener {
override fun prepareChange(events: List<VFileEvent>): AsyncFileListener.ChangeApplier? {
return service<StorageVirtualFileTrackerHolder>().tracker.prepare(events)
}
}
private fun createDefaultVirtualTracker(componentManager: ComponentManager?): StorageVirtualFileTracker? {
if (componentManager == null) {
return null
}
val tracker = service<StorageVirtualFileTrackerHolder>().tracker
Disposer.register(componentManager, Disposable {
tracker.remove { it.storageManager.componentManager === componentManager }
})
return tracker
}

View File

@@ -3,28 +3,26 @@
package com.intellij.configurationStore
import com.intellij.openapi.components.ComponentManager
import com.intellij.openapi.components.StateStorage
import com.intellij.openapi.components.impl.stores.FileStorageCoreUtil
import com.intellij.openapi.components.impl.stores.IComponentStore
import com.intellij.openapi.components.stateStore
import com.intellij.openapi.module.Module
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.AsyncFileListener
import com.intellij.openapi.vfs.VfsUtil
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.openapi.vfs.newvfs.BulkFileListener
import com.intellij.openapi.vfs.newvfs.events.*
import com.intellij.util.messages.MessageBus
import org.jetbrains.annotations.ApiStatus
import java.nio.file.Paths
import java.nio.file.Path
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentMap
import java.util.concurrent.atomic.AtomicBoolean
@ApiStatus.Internal
class StorageVirtualFileTracker(private val messageBus: MessageBus) {
private val filePathToStorage: ConcurrentMap<String, TrackedStorage> = ConcurrentHashMap()
internal class StorageVirtualFileTracker {
private val filePathToStorage = ConcurrentHashMap<String, TrackedStorage>()
@Volatile
private var hasDirectoryBasedStorages = false
private val vfsListenerAdded = AtomicBoolean()
@Volatile
private var vfsListenerIsActive = false
interface TrackedStorage : StateStorage {
val storageManager: StateStorageManagerImpl
@@ -36,9 +34,7 @@ class StorageVirtualFileTracker(private val messageBus: MessageBus) {
hasDirectoryBasedStorages = true
}
if (vfsListenerAdded.compareAndSet(false, true)) {
addVfsChangesListener()
}
vfsListenerIsActive = true
}
fun remove(path: String) {
@@ -49,79 +45,92 @@ class StorageVirtualFileTracker(private val messageBus: MessageBus) {
filePathToStorage.values.removeIf(filter)
}
private fun addVfsChangesListener() {
messageBus.connect().subscribe(VirtualFileManager.VFS_CHANGES, object : BulkFileListener {
override fun after(events: List<VFileEvent>) {
var storageEvents: LinkedHashMap<ComponentManager, LinkedHashSet<StateStorage>>? = null
eventLoop@ for (event in events) {
var storage: StateStorage?
if (event is VFilePropertyChangeEvent && VirtualFile.PROP_NAME == event.propertyName) {
val oldPath = event.oldPath
storage = filePathToStorage.remove(oldPath)
if (storage != null) {
filePathToStorage.put(event.path, storage)
if (storage is FileBasedStorage) {
storage.setFile(null, Paths.get(event.path))
}
// we don't support DirectoryBasedStorage renaming
fun prepare(events: List<VFileEvent>): AsyncFileListener.ChangeApplier? {
if (!vfsListenerIsActive) {
return null
}
// StoragePathMacros.MODULE_FILE -> old path, we must update value
(storage.storageManager as? RenameableStateStorageManager)?.pathRenamed(Paths.get(event.path), event)
}
var storageEvents: LinkedHashMap<IComponentStore, LinkedHashSet<StateStorage>>? = null
eventLoop@ for (event in events) {
var storage: StateStorage?
if (event is VFilePropertyChangeEvent && VirtualFile.PROP_NAME == event.propertyName) {
val oldPath = event.oldPath
storage = filePathToStorage.remove(oldPath)
if (storage != null) {
filePathToStorage.put(event.path, storage)
if (storage is FileBasedStorage) {
storage.setFile(null, Path.of(event.path))
}
else {
val path = event.path
storage = filePathToStorage.get(path)
// We don't care about parent directory create (because it doesn't affect anything)
// and move (because it is not a supported case),
// but we should detect deletion - but again, it is not a supported case.
// So, we don't check if some of the registered storages located inside changed directory.
// we don't support DirectoryBasedStorage renaming
// but if we have DirectoryBasedStorage, we check - if file located inside it
if (storage == null && hasDirectoryBasedStorages && path.endsWith(FileStorageCoreUtil.DEFAULT_EXT, ignoreCase = true)) {
storage = filePathToStorage.get(VfsUtil.getParentDir(path))
}
}
if (storage == null) {
continue
}
when (event) {
is VFileMoveEvent -> {
if (storage is FileBasedStorage) {
storage.setFile(null, Paths.get(event.path))
}
}
is VFileCreateEvent -> {
if (storage is FileBasedStorage && event.requestor !is SaveSession) {
storage.setFile(event.file, null)
}
}
is VFileDeleteEvent -> {
if (storage is FileBasedStorage) {
storage.setFile(null, null)
}
else {
(storage as DirectoryBasedStorage).setVirtualDir(null)
}
}
is VFileCopyEvent -> continue@eventLoop
}
if (isFireStorageFileChangedEvent(event)) {
val componentManager = storage.storageManager.componentManager!!
if (storageEvents == null) {
storageEvents = LinkedHashMap()
}
storageEvents.computeIfAbsent(componentManager) { LinkedHashSet() }.add(storage)
}
}
if (storageEvents != null) {
StoreReloadManager.getInstance().storageFilesChanged(storageEvents)
// StoragePathMacros.MODULE_FILE -> old path, we must update value
(storage.storageManager as? RenameableStateStorageManager)?.pathRenamed(Path.of(event.path), event)
}
}
})
else {
val path = event.path
storage = filePathToStorage.get(path)
// We don't care about parent directory create (because it doesn't affect anything)
// and move (because it is not a supported case),
// but we should detect deletion - but again, it is not a supported case.
// So, we don't check if some of the registered storages located inside changed directory.
// but if we have DirectoryBasedStorage, we check - if file located inside it
if (storage == null && hasDirectoryBasedStorages && path.endsWith(FileStorageCoreUtil.DEFAULT_EXT, ignoreCase = true)) {
storage = filePathToStorage.get(VfsUtil.getParentDir(path))
}
}
if (storage == null) {
continue
}
when (event) {
is VFileMoveEvent -> {
if (storage is FileBasedStorage) {
storage.setFile(null, Path.of(event.path))
}
}
is VFileCreateEvent -> {
if (storage is FileBasedStorage && event.requestor !is SaveSession) {
storage.setFile(event.file, null)
}
}
is VFileDeleteEvent -> {
if (storage is FileBasedStorage) {
storage.setFile(null, null)
}
else {
(storage as DirectoryBasedStorage).setVirtualDir(null)
}
}
is VFileCopyEvent -> continue@eventLoop
}
if (isFireStorageFileChangedEvent(event)) {
val componentManager = storage.storageManager.componentManager!!
if (storageEvents == null) {
storageEvents = LinkedHashMap()
}
storageEvents.computeIfAbsent(componentManager.stateStore) { LinkedHashSet() }.add(storage)
}
}
if (storageEvents == null) {
return null
}
return object : AsyncFileListener.ChangeApplier {
override fun afterVfsChange() {
for ((store, storages) in storageEvents) {
val project: Project = when (val componentManager = store.storageManager.componentManager) {
is Project -> componentManager
is Module -> componentManager.project
else -> continue
}
StoreReloadManager.getInstance(project).storageFilesChanged(store, storages)
}
}
}
}
}

View File

@@ -4,25 +4,23 @@ package com.intellij.configurationStore
import com.intellij.configurationStore.schemeManager.SchemeChangeApplicator
import com.intellij.configurationStore.schemeManager.SchemeChangeEvent
import com.intellij.ide.impl.OpenProjectTask
import com.intellij.openapi.application.*
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.ApplicationNamesInfo
import com.intellij.openapi.application.EDT
import com.intellij.openapi.application.ModalityState
import com.intellij.openapi.application.ex.ApplicationManagerEx
import com.intellij.openapi.components.ComponentManager
import com.intellij.openapi.components.StateStorage
import com.intellij.openapi.components.impl.stores.IComponentStore
import com.intellij.openapi.components.impl.stores.IProjectStore
import com.intellij.openapi.components.stateStore
import com.intellij.openapi.diagnostic.debug
import com.intellij.openapi.diagnostic.getOrLogException
import com.intellij.openapi.module.Module
import com.intellij.openapi.options.Scheme
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.ProjectManager
import com.intellij.openapi.project.ProjectReloadState
import com.intellij.openapi.project.ex.ProjectManagerEx
import com.intellij.openapi.ui.Messages
import com.intellij.openapi.util.Key
import com.intellij.openapi.util.Ref
import com.intellij.openapi.util.UserDataHolderEx
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileManagerListener
import com.intellij.ui.AppUIUtil
@@ -35,35 +33,43 @@ import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.debounce
import org.jetbrains.annotations.ApiStatus
import java.nio.file.Paths
import java.nio.file.Path
import java.util.concurrent.atomic.AtomicInteger
import java.util.concurrent.atomic.AtomicReference
import kotlin.time.Duration.Companion.milliseconds
private val CHANGED_FILES_KEY = Key<MutableMap<ComponentStoreImpl, MutableSet<StateStorage>>>("CHANGED_FILES_KEY")
private val CHANGED_SCHEMES_KEY = Key<MutableMap<SchemeChangeApplicator<*,*>, MutableSet<SchemeChangeEvent<*,*>>>>("CHANGED_SCHEMES_KEY")
@ApiStatus.Internal
internal class StoreReloadManagerImpl(cs: CoroutineScope) : StoreReloadManager {
internal class StoreReloadManagerImpl(coroutineScope: CoroutineScope, private val project: Project) : StoreReloadManager {
private val reloadBlockCount = AtomicInteger()
private val blockStackTrace = AtomicReference<Throwable?>()
private val changedApplicationFiles = LinkedHashSet<StateStorage>()
private val changedStorages = LinkedHashMap<ComponentStoreImpl, MutableSet<StateStorage>>()
private val changedSchemes = LinkedHashMap<SchemeChangeApplicator<*,*>, MutableSet<SchemeChangeEvent<*,*>>>()
private val changedFilesRequests = MutableSharedFlow<Unit>(replay=1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
init {
@OptIn(FlowPreview::class)
cs.launch(CoroutineName("configuration store reload request flow processing")) {
coroutineScope.launch(CoroutineName("configuration store reload request flow processing")) {
changedFilesRequests
.debounce(300.milliseconds)
.collect {
doReload()
}
}
project.messageBus.simpleConnect().subscribe(VirtualFileManagerListener.TOPIC, object : VirtualFileManagerListener {
override fun beforeRefreshStart(asynchronous: Boolean) {
blockReloadingProjectOnExternalChanges()
}
override fun afterRefreshFinish(asynchronous: Boolean) {
unblockReloadingProjectOnExternalChanges()
}
})
}
private suspend fun doReload() {
if (isReloadBlocked() || !tryToReloadApplication()) {
if (isReloadBlocked()) {
return
}
@@ -87,10 +93,8 @@ internal class StoreReloadManagerImpl(cs: CoroutineScope) : StoreReloadManager {
@RequiresEdt
private suspend fun applyProjectChanges(project: Project, projectsToReload: LinkedHashSet<Project>) {
val changedSchemes = CHANGED_SCHEMES_KEY.getAndClear(project as UserDataHolderEx)
val changedStorages = CHANGED_FILES_KEY.getAndClear(project as UserDataHolderEx)
if ((changedSchemes.isNullOrEmpty()) && (changedStorages.isNullOrEmpty())
&& !mayHaveAdditionalConfigurations(project)) {
if (changedSchemes.isEmpty() && changedStorages.isEmpty()
&& !JpsProjectModelSynchronizer.getInstance(project).needToReloadProjectEntities()) {
return
}
@@ -98,26 +102,22 @@ internal class StoreReloadManagerImpl(cs: CoroutineScope) : StoreReloadManager {
publisher.onBatchUpdateStarted()
try {
// reload schemes first because project file can refer to scheme (e.g. inspection profile)
if (changedSchemes != null) {
for ((tracker, files) in changedSchemes) {
runCatching {
SlowOperations.knownIssue("IDEA-307617, EA-680581").use {
@Suppress("UNCHECKED_CAST")
(tracker as SchemeChangeApplicator<Scheme, Scheme>).reload(files as Set<SchemeChangeEvent<Scheme, Scheme>>)
}
}.getOrLogException(LOG)
}
for ((tracker, files) in changedSchemes) {
runCatching {
SlowOperations.knownIssue("IDEA-307617, EA-680581").use {
@Suppress("UNCHECKED_CAST")
(tracker as SchemeChangeApplicator<Scheme, Scheme>).reload(files as Set<SchemeChangeEvent<Scheme, Scheme>>)
}
}.getOrLogException(LOG)
}
if (changedStorages != null) {
for ((store, storages) in changedStorages) {
if ((store.storageManager as? StateStorageManagerImpl)?.componentManager?.isDisposed == true) {
continue
}
for ((store, storages) in changedStorages) {
if ((store.storageManager as? StateStorageManagerImpl)?.componentManager?.isDisposed == true) {
continue
}
if (reloadStore(storages, store) == ReloadComponentStoreStatus.RESTART_AGREED) {
projectsToReload.add(project)
}
if (reloadStore(storages, store) == ReloadComponentStoreStatus.RESTART_AGREED) {
projectsToReload.add(project)
}
}
@@ -128,33 +128,18 @@ internal class StoreReloadManagerImpl(cs: CoroutineScope) : StoreReloadManager {
}
}
private fun mayHaveAdditionalConfigurations(project: Project): Boolean {
return JpsProjectModelSynchronizer.getInstance(project).needToReloadProjectEntities()
}
internal class MyVirtualFileManagerListener : VirtualFileManagerListener {
private val manager = StoreReloadManager.getInstance()
override fun beforeRefreshStart(asynchronous: Boolean) {
manager.blockReloadingProjectOnExternalChanges()
}
override fun afterRefreshFinish(asynchronous: Boolean) {
manager.unblockReloadingProjectOnExternalChanges()
}
}
override fun isReloadBlocked(): Boolean {
val count = reloadBlockCount.get()
LOG.debug { "[RELOAD] myReloadBlockCount = $count" }
return count > 0
}
override fun saveChangedProjectFile(file: VirtualFile, project: Project) {
val storageManager = (project.stateStore as ComponentStoreImpl).storageManager as? StateStorageManagerImpl ?: return
override fun saveChangedProjectFile(file: VirtualFile) {
val store = project.stateStore as ComponentStoreImpl
val storageManager = store.storageManager as? StateStorageManagerImpl ?: return
storageManager.getCachedFileStorages(listOf(storageManager.collapseMacro(file.path))).firstOrNull()?.let {
// if empty, so, storage is not yet loaded, so, we don't have to reload
storageFilesChanged(mapOf(project to listOf(it)))
storageFilesChanged(store, listOf(it))
}
}
@@ -187,58 +172,37 @@ internal class StoreReloadManagerImpl(cs: CoroutineScope) : StoreReloadManager {
doReload()
}
override fun reloadProject(project: Project) {
CHANGED_FILES_KEY.set(project, null)
override fun reloadProject() {
changedStorages.clear()
doReloadProject(project)
}
override fun storageFilesChanged(componentManagerToStorages: Map<ComponentManager, Collection<StateStorage>>) {
if (componentManagerToStorages.isEmpty()) {
return
}
override fun storageFilesChanged(store: IComponentStore, storages: Collection<StateStorage>) {
if (LOG.isDebugEnabled) {
LOG.debug("[RELOAD] registering to reload: ${componentManagerToStorages.map { "${it.key}: ${it.value.joinToString()}" }.joinToString("\n")}", Exception())
LOG.debug("[RELOAD] registering to reload: ${storages.joinToString("\n")}", Exception())
}
for ((componentManager, storages) in componentManagerToStorages) {
val project: Project? = when (componentManager) {
is Project -> componentManager
is Module -> componentManager.project
else -> null
}
synchronized(changedStorages) {
changedStorages.computeIfAbsent(store as ComponentStoreImpl) { LinkedHashSet() }.addAll(storages)
}
if (project == null) {
val changes = changedApplicationFiles
synchronized(changes) {
changes.addAll(storages)
}
}
else {
val changes = CHANGED_FILES_KEY.get(project) ?: (project as UserDataHolderEx).putUserDataIfAbsent(CHANGED_FILES_KEY, linkedMapOf())
synchronized(changes) {
changes.computeIfAbsent(componentManager.stateStore as ComponentStoreImpl) { LinkedHashSet() }.addAll(storages)
}
}
for (storage in storages) {
if (storage is StateStorageBase<*>) {
storage.disableSaving()
}
for (storage in storages) {
if (storage is StateStorageBase<*>) {
storage.disableSaving()
}
}
scheduleProcessingChangedFiles()
}
internal fun <T : Scheme, M:T>registerChangedSchemes(events: List<SchemeChangeEvent<T,M>>, schemeFileTracker: SchemeChangeApplicator<T,M>, project: Project) {
internal fun <T : Scheme, M : T> registerChangedSchemes(events: List<SchemeChangeEvent<T, M>>,
schemeFileTracker: SchemeChangeApplicator<T, M>) {
if (LOG.isDebugEnabled) {
LOG.debug("[RELOAD] Registering schemes to reload: $events", Exception())
}
val changes = CHANGED_SCHEMES_KEY.get(project) ?: (project as UserDataHolderEx).putUserDataIfAbsent(CHANGED_SCHEMES_KEY, linkedMapOf())
synchronized(changes) {
changes.computeIfAbsent(schemeFileTracker) { LinkedHashSet() }.addAll(events)
synchronized(changedSchemes) {
changedSchemes.computeIfAbsent(schemeFileTracker) { LinkedHashSet() }.addAll(events)
}
scheduleProcessingChangedFiles()
@@ -249,21 +213,6 @@ internal class StoreReloadManagerImpl(cs: CoroutineScope) : StoreReloadManager {
check(changedFilesRequests.tryEmit(Unit))
}
}
private fun tryToReloadApplication(): Boolean {
if (ApplicationManager.getApplication().isDisposed) {
return false
}
if (changedApplicationFiles.isEmpty()) {
return true
}
val changes = LinkedHashSet(changedApplicationFiles)
changedApplicationFiles.clear()
return reloadAppStore(changes)
}
}
fun reloadAppStore(changes: Set<StateStorage>): Boolean {
@@ -374,31 +323,17 @@ internal enum class ReloadComponentStoreStatus {
SUCCESS
}
private fun <T : Any> Key<T>.getAndClear(holder: UserDataHolderEx): T? {
val value = holder.getUserData(this) ?: return null
holder.replace(this, value, null)
return value
}
private fun doReloadProject(project: Project) {
val projectRef = Ref.create(project)
ProjectReloadState.getInstance(project).onBeforeAutomaticProjectReload()
AppUIExecutor.onWriteThread(ModalityState.NON_MODAL).later().submit {
LOG.debug("Reloading project.")
val project1 = projectRef.get()
// Let it go
projectRef.set(null)
ApplicationManager.getApplication().invokeLater({
LOG.debug("Reloading project")
if (project1.isDisposed) {
return@submit
// must compute here, before dispose of the project
val presentableUrl = project.presentableUrl!!
if (!ProjectManager.getInstance().closeAndDispose(project)) {
return@invokeLater
}
// must compute here, before project dispose
val presentableUrl = project1.presentableUrl!!
if (!ProjectManager.getInstance().closeAndDispose(project1)) {
return@submit
}
ProjectManagerEx.getInstanceEx().openProject(Paths.get(presentableUrl), OpenProjectTask())
}
ProjectManagerEx.getInstanceEx().openProject(Path.of(presentableUrl), OpenProjectTask())
}, ModalityState.NON_MODAL, project.disposed)
}

View File

@@ -64,7 +64,7 @@ internal class SchemeFileTracker<T: Scheme, M:T>(private val schemeManager: Sche
}
if (list.isNotEmpty()) {
(StoreReloadManager.getInstance() as StoreReloadManagerImpl).registerChangedSchemes(list, applicator, project)
(StoreReloadManager.getInstance(project) as StoreReloadManagerImpl).registerChangedSchemes(list, applicator)
}
}

View File

@@ -5,6 +5,7 @@ import com.intellij.ProjectTopics
import com.intellij.ide.highlighter.ModuleFileType
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.EDT
import com.intellij.openapi.application.writeAction
import com.intellij.openapi.components.StateStorageOperation
import com.intellij.openapi.components.StoragePathMacros
import com.intellij.openapi.components.stateStore
@@ -76,12 +77,7 @@ internal class ModuleStoreRenameTest {
// should be invoked after project tearDown
override fun after() {
(ApplicationManager.getApplication().stateStore.storageManager as StateStorageManagerImpl).getVirtualFileTracker()!!.remove {
if (it.storageManager.componentManager == module) {
throw AssertionError("Storage manager is not disposed, module $module, storage $it")
}
false
}
checkStorageIsNotTracked(module)
}
},
DisposeModulesRule(projectRule)
@@ -99,10 +95,8 @@ internal class ModuleStoreRenameTest {
val oldName = module.name
val newName = "foo"
withContext(Dispatchers.EDT) {
ApplicationManager.getApplication().runWriteAction {
projectRule.project.modifyModules { renameModule(module, newName) }
}
writeAction {
projectRule.project.modifyModules { renameModule(module, newName) }
}
assertModuleFileRenamed(newName, oldFile)
assertThat(oldModuleNames).containsOnly(oldName)
@@ -178,20 +172,17 @@ internal class ModuleStoreRenameTest {
val storage = module.storage
val parentVirtualDir = storage.getVirtualFile(StateStorageOperation.WRITE)!!.parent
val src = VfsTestUtil.createDir(parentVirtualDir, "foo")
withContext(Dispatchers.EDT) {
ApplicationManager.getApplication().runWriteAction {
PsiTestUtil.addSourceContentToRoots(module, src, false)
}
writeAction {
PsiTestUtil.addSourceContentToRoots(module, src, false)
}
saveProjectState()
val rootManager = module.rootManager as ModuleRootManagerEx
val stateModificationCount = rootManager.modificationCountForTests
withContext(Dispatchers.EDT) {
ApplicationManager.getApplication().runWriteAction {
src.rename(null, "bar.dot")
}
writeAction {
src.rename(null, "bar.dot")
}
assertThat(stateModificationCount).isLessThan(rootManager.modificationCountForTests)

View File

@@ -4,7 +4,7 @@ package com.intellij.configurationStore
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.EDT
import com.intellij.openapi.application.ex.PathManagerEx
import com.intellij.openapi.application.runWriteAction
import com.intellij.openapi.application.writeAction
import com.intellij.openapi.components.StoragePathMacros
import com.intellij.openapi.components.stateStore
import com.intellij.openapi.module.Module
@@ -157,7 +157,7 @@ class ModuleStoreTest {
removeContentRoot(m2)
}
StoreReloadManager.getInstance().reloadChangedStorageFiles()
StoreReloadManager.getInstance(projectRule.project).reloadChangedStorageFiles()
assertChangesApplied(m1)
assertChangesApplied(m2)
@@ -196,11 +196,11 @@ class ModuleStoreTest {
val moduleName = "tmp-module-${Ksuid.generate()}"
val contentRoot = tempDirManager.createVirtualDir()
withContext(Dispatchers.EDT) {
val module = runWriteAction {
ModuleManager.getInstance(project).newNonPersistentModule(moduleName, ModuleTypeId.JAVA_MODULE)
}
val module = writeAction {
ModuleManager.getInstance(project).newNonPersistentModule(moduleName, ModuleTypeId.JAVA_MODULE)
}
withContext(Dispatchers.EDT) {
SoftAssertions.assertSoftly {
it.assertThat(module.moduleFilePath).isEmpty()
it.assertThat(module.isLoaded).isTrue
@@ -239,7 +239,7 @@ class ModuleStoreTest {
}
}
inline suspend fun <T> Module.useAndDispose(task: Module.() -> T): T {
suspend inline fun <T> Module.useAndDispose(task: Module.() -> T): T {
try {
return task()
}
@@ -252,9 +252,7 @@ inline suspend fun <T> Module.useAndDispose(task: Module.() -> T): T {
suspend fun ProjectRule.loadModule(file: VirtualFile): Module {
val project = project
return withContext(Dispatchers.EDT) {
runWriteAction { ModuleManager.getInstance(project).loadModule(file.toNioPath()) }
}
return writeAction { ModuleManager.getInstance(project).loadModule(file.toNioPath()) }
}
val Module.contentRootUrls: Array<String>
@@ -262,9 +260,7 @@ val Module.contentRootUrls: Array<String>
internal suspend fun ProjectRule.createModule(path: Path): Module {
val project = project
return withContext(Dispatchers.EDT) {
runWriteAction {
ModuleManager.getInstance(project).newModule(path, ModuleTypeId.JAVA_MODULE)
}
return writeAction {
ModuleManager.getInstance(project).newModule(path, ModuleTypeId.JAVA_MODULE)
}
}

View File

@@ -74,7 +74,7 @@ internal class ProjectStoreTest {
file.write(file.readText().replace("""<option name="AAvalue" value="foo" />""", """<option name="AAvalue" value="newValue" />"""))
refreshProjectConfigDir(project)
StoreReloadManager.getInstance().reloadChangedStorageFiles()
StoreReloadManager.getInstance(project).reloadChangedStorageFiles()
assertThat(testComponent.state).isEqualTo(TestState("newValue"))

View File

@@ -62,7 +62,7 @@ public abstract class VirtualFileManager implements ModificationTracker {
* Refreshes the cached file systems information from the physical file systems asynchronously.
* Launches specified action when refresh is finished.
* <p>
* @param postAction - action which will be executed in write-action after refresh session finished.
* @param postAction - action which will be executed in write-action after the refresh session finished.
* @return refresh session ID.
*/
public abstract long asyncRefresh(@Nullable Runnable postAction);
@@ -189,12 +189,6 @@ public abstract class VirtualFileManager implements ModificationTracker {
return URLUtil.extractPath(url);
}
/**
* @deprecated Use {@link #addVirtualFileManagerListener(VirtualFileManagerListener, Disposable)}
*/
@Deprecated
public abstract void addVirtualFileManagerListener(@NotNull VirtualFileManagerListener listener);
public abstract void addVirtualFileManagerListener(@NotNull VirtualFileManagerListener listener, @NotNull Disposable parentDisposable);
/**
@@ -210,7 +204,7 @@ public abstract class VirtualFileManager implements ModificationTracker {
/**
* @return a number that's incremented every time something changes in the VFS, i.e. file hierarchy, names, flags, attributes, contents.
* This only counts modifications done in current IDE session.
* This only counts modifications done in the current IDE session.
* @see #getStructureModificationCount()
*/
@Override
@@ -218,7 +212,7 @@ public abstract class VirtualFileManager implements ModificationTracker {
/**
* @return a number that's incremented every time something changes in the VFS structure, i.e. file hierarchy or names.
* This only counts modifications done in current IDE session.
* This only counts modifications done in the current IDE session.
* @see #getModificationCount()
*/
public abstract long getStructureModificationCount();

View File

@@ -1,14 +1,20 @@
// 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.vfs;
import com.intellij.util.messages.Topic;
import java.util.EventListener;
/**
* Message bus cannot be used because before / after events are not supported - order of events maybe changed by message bus.
*
* <p>
* Use extension point: {@code <extensionPoint name="virtualFileManagerListener" interface="com.example.Foo"/>}
*/
public interface VirtualFileManagerListener extends EventListener {
@Topic.AppLevel
Topic<VirtualFileManagerListener> TOPIC =
new Topic<>(VirtualFileManagerListener.class, Topic.BroadcastDirection.TO_DIRECT_CHILDREN, true);
default void beforeRefreshStart(boolean asynchronous) {
}

View File

@@ -2,7 +2,9 @@
package com.intellij.openapi.vfs.impl;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.*;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.application.ex.ApplicationManagerEx;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.ExtensionPoint;
@@ -39,7 +41,7 @@ public class VirtualFileManagerImpl extends VirtualFileManagerEx implements Disp
protected static final Logger LOG = Logger.getInstance(VirtualFileManagerImpl.class);
// do not use extension point name to avoid map lookup on each event publishing
private static final ExtensionPointImpl<VirtualFileManagerListener> MANAGER_LISTENER_EP =
private static final ExtensionPointImpl<@NotNull VirtualFileManagerListener> MANAGER_LISTENER_EP =
((ExtensionsAreaImpl)ApplicationManager.getApplication().getExtensionArea()).getExtensionPoint("com.intellij.virtualFileManagerListener");
private final List<? extends VirtualFileSystem> myPreCreatedFileSystems;
@@ -172,14 +174,9 @@ public class VirtualFileManagerImpl extends VirtualFileManagerEx implements Disp
myVirtualFileListenerMulticaster.removeListener(listener);
}
@Override
public void addVirtualFileManagerListener(@NotNull VirtualFileManagerListener listener) {
myVirtualFileManagerListeners.add(listener);
}
@Override
public void addVirtualFileManagerListener(@NotNull VirtualFileManagerListener listener, @NotNull Disposable parentDisposable) {
addVirtualFileManagerListener(listener);
myVirtualFileManagerListeners.add(listener);
Disposer.register(parentDisposable, () -> removeVirtualFileManagerListener(listener));
}
@@ -202,16 +199,16 @@ public class VirtualFileManagerImpl extends VirtualFileManagerEx implements Disp
@Override
public void notifyPropertyChanged(@NotNull VirtualFile virtualFile, @VirtualFile.PropName @NotNull String property, Object oldValue, Object newValue) {
Application app = ApplicationManager.getApplication();
AppUIExecutor.onWriteThread(ModalityState.NON_MODAL).later().expireWith(app).submit(() -> {
ApplicationManager.getApplication().invokeLater(() -> {
if (virtualFile.isValid()) {
WriteAction.run(() -> {
ApplicationManager.getApplication().runWriteAction(() -> {
List<VFileEvent> events = Collections.singletonList(new VFilePropertyChangeEvent(this, virtualFile, property, oldValue, newValue, false));
BulkFileListener listener = app.getMessageBus().syncPublisher(VirtualFileManager.VFS_CHANGES);
listener.before(events);
listener.after(events);
});
}
});
}, ModalityState.NON_MODAL);
}
@Override

View File

@@ -165,7 +165,7 @@ public final class MergeUtil {
public static void reportProjectFileChangeIfNeeded(@Nullable Project project, @Nullable VirtualFile file) {
if (project != null && file != null && isProjectFile(file)) {
StoreReloadManager.getInstance().saveChangedProjectFile(file, project);
StoreReloadManager.Companion.getInstance(project).saveChangedProjectFile(file);
}
}

View File

@@ -26,7 +26,10 @@ import com.intellij.openapi.module.EmptyModuleType
import com.intellij.openapi.module.Module
import com.intellij.openapi.module.ModuleManager
import com.intellij.openapi.module.ModuleTypeId
import com.intellij.openapi.project.*
import com.intellij.openapi.project.ExternalStorageConfigurationManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.doNotEnableExternalStorageByDefaultInTests
import com.intellij.openapi.project.getProjectDataPathRoot
import com.intellij.openapi.roots.*
import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar
import com.intellij.openapi.util.Disposer
@@ -74,6 +77,7 @@ class ExternalSystemStorageTest {
val appRule = ApplicationRule()
}
@JvmField
@Rule
val disposableRule = DisposableRule()
@@ -84,7 +88,8 @@ class ExternalSystemStorageTest {
@Test
fun `save single mavenized module`() = saveProjectInExternalStorageAndCheckResult("singleModule") { project, projectDir ->
val module = ModuleManager.getInstance(project).newModule(projectDir.resolve("test.iml").systemIndependentPath, ModuleTypeId.JAVA_MODULE)
val module = ModuleManager.getInstance(project).newModule(projectDir.resolve("test.iml").systemIndependentPath,
ModuleTypeId.JAVA_MODULE)
ModuleRootModificationUtil.addContentRoot(module, projectDir.systemIndependentPath)
ExternalSystemModulePropertyManager.getInstance(module).setMavenized(true)
}
@@ -100,7 +105,8 @@ class ExternalSystemStorageTest {
}
@Test
fun `save single module from external system`() = saveProjectInExternalStorageAndCheckResult("singleModuleFromExternalSystem") { project, projectDir ->
fun `save single module from external system`() = saveProjectInExternalStorageAndCheckResult(
"singleModuleFromExternalSystem") { project, projectDir ->
val module = ModuleManager.getInstance(project).newModule(projectDir.resolve("test.iml").systemIndependentPath,
ModuleTypeId.JAVA_MODULE)
ModuleRootModificationUtil.addContentRoot(module, projectDir.systemIndependentPath)
@@ -111,33 +117,31 @@ class ExternalSystemStorageTest {
fun `applying external system options twice`() {
createProjectAndUseInLoadComponentStateMode(tempDirManager, directoryBased = true, useDefaultProjectSettings = false) { project ->
runBlocking {
withContext(Dispatchers.EDT) {
runWriteAction {
val projectDir = project.stateStore.directoryStorePath!!.parent
val module = ModuleManager.getInstance(project).newModule(projectDir.resolve("test.iml").systemIndependentPath,
ModuleTypeId.JAVA_MODULE)
ModuleRootModificationUtil.addContentRoot(module, projectDir.systemIndependentPath)
writeAction {
val projectDir = project.stateStore.directoryStorePath!!.parent
val module = ModuleManager.getInstance(project).newModule(projectDir.resolve("test.iml").systemIndependentPath,
ModuleTypeId.JAVA_MODULE)
ModuleRootModificationUtil.addContentRoot(module, projectDir.systemIndependentPath)
val propertyManager = ExternalSystemModulePropertyManager.getInstance(module)
val propertyManager = ExternalSystemModulePropertyManager.getInstance(module)
val systemId = ProjectSystemId("GRADLE")
val moduleData = ModuleData("test", systemId, "", "", "", projectDir.systemIndependentPath).also {
it.group = "group"
it.version = "42.0"
}
val projectData = ProjectData(systemId, "", "", projectDir.systemIndependentPath)
val modelsProvider = IdeModifiableModelsProviderImpl(project)
propertyManager.setExternalOptions(systemId, moduleData, projectData)
propertyManager.setExternalOptions(systemId, moduleData, projectData)
val externalOptionsFromBuilder = modelsProvider.actualStorageBuilder
.entities(ModuleEntity::class.java).singleOrNull()?.exModuleOptions
assertEquals("GRADLE", externalOptionsFromBuilder?.externalSystem)
val systemId = ProjectSystemId("GRADLE")
val moduleData = ModuleData("test", systemId, "", "", "", projectDir.systemIndependentPath).also {
it.group = "group"
it.version = "42.0"
}
val projectData = ProjectData(systemId, "", "", projectDir.systemIndependentPath)
val modelsProvider = IdeModifiableModelsProviderImpl(project)
propertyManager.setExternalOptions(systemId, moduleData, projectData)
propertyManager.setExternalOptions(systemId, moduleData, projectData)
val externalOptionsFromBuilder = modelsProvider.actualStorageBuilder
.entities(ModuleEntity::class.java).singleOrNull()?.exModuleOptions
assertEquals("GRADLE", externalOptionsFromBuilder?.externalSystem)
}
}
}
@@ -155,7 +159,8 @@ class ExternalSystemStorageTest {
}
@Test
fun `save single module from external system in internal storage`() = saveProjectInInternalStorageAndCheckResult("singleModuleFromExternalSystemInInternalStorage") { project, projectDir ->
fun `save single module from external system in internal storage`() = saveProjectInInternalStorageAndCheckResult(
"singleModuleFromExternalSystemInInternalStorage") { project, projectDir ->
val module = ModuleManager.getInstance(project).newModule(projectDir.resolve("test.iml").systemIndependentPath,
ModuleTypeId.JAVA_MODULE)
ModuleRootModificationUtil.addContentRoot(module, projectDir.systemIndependentPath)
@@ -163,7 +168,8 @@ class ExternalSystemStorageTest {
}
@Test
fun `load single module from external system in internal storage`() = loadProjectAndCheckResults("singleModuleFromExternalSystemInInternalStorage") { project ->
fun `load single module from external system in internal storage`() = loadProjectAndCheckResults(
"singleModuleFromExternalSystemInInternalStorage") { project ->
val module = ModuleManager.getInstance(project).modules.single()
assertThat(module.name).isEqualTo("test")
assertThat(module.moduleTypeName).isEqualTo(ModuleTypeId.JAVA_MODULE)
@@ -196,7 +202,8 @@ class ExternalSystemStorageTest {
@Test
fun `save imported module in internal storage`() = saveProjectInInternalStorageAndCheckResult("singleModuleInInternalStorage") { project, projectDir ->
fun `save imported module in internal storage`() = saveProjectInInternalStorageAndCheckResult(
"singleModuleInInternalStorage") { project, projectDir ->
val module = ModuleManager.getInstance(project).newModule(projectDir.resolve("test.iml").systemIndependentPath,
ModuleTypeId.JAVA_MODULE)
ModuleRootModificationUtil.addContentRoot(module, projectDir.systemIndependentPath)
@@ -215,9 +222,11 @@ class ExternalSystemStorageTest {
@Test
fun `save mixed modules`() = saveProjectInExternalStorageAndCheckResult("mixedModules") { project, projectDir ->
val regular = ModuleManager.getInstance(project).newModule(projectDir.resolve("regular.iml").systemIndependentPath, ModuleTypeId.JAVA_MODULE)
val regular = ModuleManager.getInstance(project).newModule(projectDir.resolve("regular.iml").systemIndependentPath,
ModuleTypeId.JAVA_MODULE)
ModuleRootModificationUtil.addContentRoot(regular, projectDir.resolve("regular").systemIndependentPath)
val imported = ModuleManager.getInstance(project).newModule(projectDir.resolve("imported.iml").systemIndependentPath, ModuleTypeId.JAVA_MODULE)
val imported = ModuleManager.getInstance(project).newModule(projectDir.resolve("imported.iml").systemIndependentPath,
ModuleTypeId.JAVA_MODULE)
ModuleRootModificationUtil.addContentRoot(imported, projectDir.resolve("imported").systemIndependentPath)
ExternalSystemModulePropertyManager.getInstance(imported).setMavenized(true)
ExternalSystemModulePropertyManager.getInstance(imported).setLinkedProjectPath("${project.basePath}/imported")
@@ -251,7 +260,8 @@ class ExternalSystemStorageTest {
assertThat(regular.moduleTypeName).isEqualTo(ModuleTypeId.JAVA_MODULE)
assertThat(imported.moduleFilePath).isEqualTo("${project.basePath}/imported.iml")
assertThat(regular.moduleFilePath).isEqualTo("${project.basePath}/regular.iml")
assertThat(ModuleRootManager.getInstance(imported).contentRootUrls.single()).isEqualTo(VfsUtil.pathToUrl("${project.basePath}/imported"))
assertThat(ModuleRootManager.getInstance(imported).contentRootUrls.single()).isEqualTo(
VfsUtil.pathToUrl("${project.basePath}/imported"))
assertThat(ModuleRootManager.getInstance(regular).contentRootUrls.single()).isEqualTo(VfsUtil.pathToUrl("${project.basePath}/regular"))
val externalModuleProperty = ExternalSystemModulePropertyManager.getInstance(imported)
assertThat(externalModuleProperty.isMavenized()).isTrue()
@@ -260,8 +270,10 @@ class ExternalSystemStorageTest {
}
@Test
fun `save regular facet in imported module`() = saveProjectInExternalStorageAndCheckResult("regularFacetInImportedModule") { project, projectDir ->
val module = ModuleManager.getInstance(project).newModule(projectDir.resolve("test.iml").systemIndependentPath, ModuleTypeId.JAVA_MODULE)
fun `save regular facet in imported module`() = saveProjectInExternalStorageAndCheckResult(
"regularFacetInImportedModule") { project, projectDir ->
val module = ModuleManager.getInstance(project).newModule(projectDir.resolve("test.iml").systemIndependentPath,
ModuleTypeId.JAVA_MODULE)
ModuleRootModificationUtil.addContentRoot(module, projectDir.systemIndependentPath)
FacetManager.getInstance(module).addFacet(MockFacetType.getInstance(), "regular", null)
ExternalSystemModulePropertyManager.getInstance(module).setMavenized(true)
@@ -291,18 +303,21 @@ class ExternalSystemStorageTest {
loadProjectAndCheckResults("singleModuleInInternalAndExternalStorages") { project ->
val modules = ModuleManager.getInstance(project).modules
assertThat(modules).hasSize(1)
val testModule= modules[0]
val testModule = modules[0]
assertThat(testModule.name).isEqualTo("test")
assertThat(testModule.moduleTypeName).isEqualTo(ModuleTypeId.JAVA_MODULE)
assertThat(testModule.moduleFilePath).isEqualTo("${project.basePath}/test.iml")
assertThat(ModuleRootManager.getInstance(testModule).contentRootUrls.single()).isEqualTo(VfsUtil.pathToUrl("${project.basePath}/test"))
assertThat(ModuleRootManager.getInstance(testModule).contentRootUrls.single()).isEqualTo(
VfsUtil.pathToUrl("${project.basePath}/test"))
val externalModuleProperty = ExternalSystemModulePropertyManager.getInstance(testModule)
assertThat(externalModuleProperty.isMavenized()).isTrue()
}
@Test
fun `save imported facet in imported module`() = saveProjectInExternalStorageAndCheckResult("importedFacetInImportedModule") { project, projectDir ->
val imported = ModuleManager.getInstance(project).newModule(projectDir.resolve("imported.iml").systemIndependentPath, ModuleTypeId.JAVA_MODULE)
fun `save imported facet in imported module`() = saveProjectInExternalStorageAndCheckResult(
"importedFacetInImportedModule") { project, projectDir ->
val imported = ModuleManager.getInstance(project).newModule(projectDir.resolve("imported.iml").systemIndependentPath,
ModuleTypeId.JAVA_MODULE)
val facetRoot = VfsUtilCore.pathToUrl(projectDir.resolve("facet").systemIndependentPath)
addFacet(imported, SerializationConstants.MAVEN_EXTERNAL_SOURCE_ID, "imported", listOf(facetRoot))
ExternalSystemModulePropertyManager.getInstance(imported).setMavenized(true)
@@ -521,7 +536,8 @@ class ExternalSystemStorageTest {
@Test
fun `test facet and libraries saved in internal store after IDE reload`() {
loadModifySaveAndCheck("singleModuleFacetAndLibFromExternalSystemInInternalStorage", "singleModuleFacetAndLibFromExternalSystem") { project ->
loadModifySaveAndCheck("singleModuleFacetAndLibFromExternalSystemInInternalStorage",
"singleModuleFacetAndLibFromExternalSystem") { project ->
ExternalProjectsManagerImpl.getInstance(project).setStoreExternally(true)
}
}
@@ -564,7 +580,7 @@ class ExternalSystemStorageTest {
WriteAction.runAndWait<RuntimeException> {
VfsUtil.markDirtyAndRefresh(false, false, false, miscFile)
}
runBlocking { StoreReloadManager.getInstance().reloadChangedStorageFiles() }
runBlocking { StoreReloadManager.getInstance(project).reloadChangedStorageFiles() }
ApplicationManager.getApplication().invokeAndWait {
PlatformTestUtil.dispatchAllInvocationEventsInIdeEventQueue()
}
@@ -585,8 +601,8 @@ class ExternalSystemStorageTest {
WriteAction.runAndWait<RuntimeException> {
VfsUtil.markDirtyAndRefresh(false, false, false, miscFile)
}
runBlocking { StoreReloadManager.getInstance().reloadChangedStorageFiles() }
ApplicationManager.getApplication().invokeAndWait{
runBlocking { StoreReloadManager.getInstance(project).reloadChangedStorageFiles() }
ApplicationManager.getApplication().invokeAndWait {
PlatformTestUtil.dispatchAllInvocationEventsInIdeEventQueue()
}
}
@@ -611,10 +627,10 @@ class ExternalSystemStorageTest {
@Test
fun `incorrect modules setup same iml`() {
loadProjectAndCheckResults("incorrectModulesSetupSameIml") { project ->
val modules = ModuleManager.getInstance(project).modules
assertEquals(1, modules.size)
}
loadProjectAndCheckResults("incorrectModulesSetupSameIml") { project ->
val modules = ModuleManager.getInstance(project).modules
assertEquals(1, modules.size)
}
}
@Test
@@ -727,7 +743,7 @@ class ExternalSystemStorageTest {
@Test
fun `test property for module`() {
loadModifySaveAndCheck("twoModules", "moduleWithTestProperties") {project ->
loadModifySaveAndCheck("twoModules", "moduleWithTestProperties") { project ->
val mainModuleName = "foo"
val testModuleName = "foo.test"
val moduleManager = ModuleManager.getInstance(project)
@@ -852,7 +868,8 @@ class ExternalSystemStorageTest {
val expectedCacheDir = expectedDir.resolve("cache")
if (Files.exists(expectedCacheDir)) {
cacheDir.toFile().assertMatches(directoryContentOf(expectedCacheDir, originalExpectedDir.resolve("cache")), FileTextMatcher.ignoreBlankLines())
cacheDir.toFile().assertMatches(directoryContentOf(expectedCacheDir, originalExpectedDir.resolve("cache")),
FileTextMatcher.ignoreBlankLines())
}
else {
assertTrue("$cacheDir doesn't exist", !Files.exists(cacheDir) || isFolderWithoutFiles(cacheDir.toFile()))
@@ -909,7 +926,7 @@ class ExternalSystemStorageTest {
}
private val MOCK_EXTERNAL_SOURCE = object: ProjectModelExternalSource {
private val MOCK_EXTERNAL_SOURCE = object : ProjectModelExternalSource {
override fun getDisplayName() = "mock"
override fun getId() = "mock"

View File

@@ -1,8 +1,8 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.configurationStore
import com.intellij.openapi.components.ComponentManager
import com.intellij.openapi.components.StateStorage
import com.intellij.openapi.components.impl.stores.IComponentStore
import com.intellij.openapi.components.service
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
@@ -10,11 +10,10 @@ import org.jetbrains.annotations.ApiStatus
interface StoreReloadManager {
companion object {
@JvmStatic
fun getInstance() = service<StoreReloadManager>()
fun getInstance(project: Project) = project.service<StoreReloadManager>()
}
fun reloadProject(project: Project)
fun reloadProject()
fun blockReloadingProjectOnExternalChanges()
@@ -26,9 +25,9 @@ interface StoreReloadManager {
@ApiStatus.Internal
fun scheduleProcessingChangedFiles()
fun saveChangedProjectFile(file: VirtualFile, project: Project)
fun saveChangedProjectFile(file: VirtualFile)
suspend fun reloadChangedStorageFiles()
fun storageFilesChanged(componentManagerToStorages: Map<ComponentManager, Collection<StateStorage>>)
fun storageFilesChanged(store: IComponentStore, storages: Collection<StateStorage>)
}

View File

@@ -1,4 +1,6 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@file:Suppress("ReplacePutWithAssignment")
package com.intellij.configurationStore
import com.intellij.ide.IdeBundle
@@ -112,7 +114,7 @@ private fun checkUnknownMacros(project: Project,
else if (Messages.showYesNoDialog(project, IdeBundle.message("dialog.message.component.could.not.be.reloaded"),
IdeBundle.message("dialog.title.configuration.changed"),
Messages.getQuestionIcon()) == Messages.YES) {
StoreReloadManager.getInstance().reloadProject(project)
StoreReloadManager.getInstance(project).reloadProject()
}
}
}

View File

@@ -212,38 +212,41 @@ fun getPerOsSettingsStorageFolderName(): String {
}
}
/**
* @param forceSavingAllSettings Whether to force save non-roamable component configuration.
*/
@CalledInAny
suspend fun saveProjectsAndApp(forceSavingAllSettings: Boolean, onlyProject: Project? = null) {
val storeReloadManager = StoreReloadManager.getInstance()
private suspend inline fun reloadChangedStorageFilesAndRun(project: Project, task: () -> Unit) {
val storeReloadManager = StoreReloadManager.getInstance(project)
storeReloadManager.reloadChangedStorageFiles()
storeReloadManager.blockReloadingProjectOnExternalChanges()
try {
val start = System.currentTimeMillis()
saveSettings(ApplicationManager.getApplication(), forceSavingAllSettings)
if (onlyProject == null) {
saveAllProjects(forceSavingAllSettings)
}
else {
saveSettings(onlyProject, forceSavingAllSettings = true)
}
val duration = System.currentTimeMillis() - start
if (duration > 1000 || LOG.isDebugEnabled) {
LOG.info("saveProjectsAndApp took $duration ms")
}
task()
}
finally {
storeReloadManager.unblockReloadingProjectOnExternalChanges()
}
}
/**
* @param forceSavingAllSettings Whether to force save non-roamable component configuration.
*/
@CalledInAny
private suspend fun saveAllProjects(forceSavingAllSettings: Boolean) {
processOpenedProjects { project ->
saveSettings(project, forceSavingAllSettings)
suspend fun saveProjectsAndApp(forceSavingAllSettings: Boolean, onlyProject: Project? = null) {
val start = System.currentTimeMillis()
saveSettings(ApplicationManager.getApplication(), forceSavingAllSettings)
if (onlyProject == null) {
processOpenedProjects { project ->
reloadChangedStorageFilesAndRun(project) {
saveSettings(project, forceSavingAllSettings)
}
}
}
else {
reloadChangedStorageFilesAndRun(onlyProject) {
saveSettings(onlyProject, forceSavingAllSettings = true)
}
}
val duration = System.currentTimeMillis() - start
if (duration > 1000 || LOG.isDebugEnabled) {
LOG.info("saveProjectsAndApp took $duration ms")
}
}

View File

@@ -12,7 +12,6 @@ import org.jetbrains.annotations.NotNull;
import java.util.Objects;
final class ReloadProjectAction extends AnAction implements DumbAware {
@Override
public @NotNull ActionUpdateThread getActionUpdateThread() {
return ActionUpdateThread.BGT;
@@ -26,6 +25,6 @@ final class ReloadProjectAction extends AnAction implements DumbAware {
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
Project project = Objects.requireNonNull(e.getProject());
StoreReloadManager.getInstance().reloadProject(project);
StoreReloadManager.Companion.getInstance(project).reloadProject();
}
}

View File

@@ -63,6 +63,7 @@ import com.intellij.openapi.wm.impl.welcomeScreen.WelcomeFrame
import com.intellij.platform.PlatformProjectOpenProcessor
import com.intellij.platform.PlatformProjectOpenProcessor.Companion.isLoadedFromCacheButHasNoModules
import com.intellij.platform.attachToProjectAsync
import com.intellij.platform.jps.model.impl.diagnostic.JpsMetrics
import com.intellij.projectImport.ProjectAttachProcessor
import com.intellij.serviceContainer.ComponentManagerImpl
import com.intellij.ui.IdeUICustomization
@@ -77,7 +78,6 @@ import kotlinx.coroutines.*
import org.jetbrains.annotations.ApiStatus.Internal
import org.jetbrains.annotations.TestOnly
import org.jetbrains.annotations.VisibleForTesting
import com.intellij.platform.jps.model.impl.diagnostic.JpsMetrics
import java.io.IOException
import java.nio.file.Files
import java.nio.file.InvalidPathException
@@ -268,7 +268,7 @@ open class ProjectManagerImpl : ProjectManagerEx(), Disposable {
override fun findOpenProjectByHash(locationHash: String?): Project? = openProjectByHash.get(locationHash)
override fun reloadProject(project: Project) {
StoreReloadManager.getInstance().reloadProject(project)
StoreReloadManager.getInstance(project).reloadProject()
}
override fun closeProject(project: Project): Boolean {
@@ -637,7 +637,7 @@ open class ProjectManagerImpl : ProjectManagerEx(), Disposable {
throw CancellationException("project is already opened")
}
// Project is loaded and is initialized, project services and components can be accessed.
// The project is loaded and is initialized, project services and components can be accessed.
// But start-up and post start-up activities are not yet executed.
if (!initFrameEarly) {
rawProjectDeferred?.complete(project)
@@ -1106,7 +1106,7 @@ private fun toCanonicalName(filePath: String): Path {
catch (ignore: InvalidPathException) {
}
catch (e: IOException) {
// OK. File does not yet exist, so its canonical path will be equal to its original path.
// the file does not yet exist, so its canonical path will be equal to its original path
}
return file
}
@@ -1327,7 +1327,7 @@ private suspend fun checkTrustedState(projectStoreBaseDir: Path): Boolean {
// this project is in recent projects => it was opened on this computer before
// => most probably we already asked about its trusted state before
// the only exception is: the project stayed in the UNKNOWN state in the previous version because it didn't utilize any dangerous features
// in this case we will ask since no UNKNOWN state is allowed, but on a later stage, when we'll be able to look into the project-wide storage
// in this case, we will ask since no UNKNOWN state is allowed, but on a later stage, when we'll be able to look into the project-wide storage
return true
}

View File

@@ -7,13 +7,12 @@ import com.intellij.openapi.components.Storage;
import com.intellij.openapi.components.StoragePathMacros;
import com.intellij.openapi.project.ProjectReloadState;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@State(
name = "ProjectReloadState",
storages = @Storage(StoragePathMacros.WORKSPACE_FILE)
)
class ProjectReloadStateImpl extends ProjectReloadState implements PersistentStateComponent<ProjectReloadStateImpl> {
final class ProjectReloadStateImpl extends ProjectReloadState implements PersistentStateComponent<ProjectReloadStateImpl> {
public static final int UNKNOWN = 0;
public static final int BEFORE_RELOAD = 1;
public static final int AFTER_RELOAD = 2;
@@ -30,9 +29,8 @@ class ProjectReloadStateImpl extends ProjectReloadState implements PersistentSta
STATE = BEFORE_RELOAD;
}
@Nullable
@Override
public ProjectReloadStateImpl getState() {
public @NotNull ProjectReloadStateImpl getState() {
return this;
}

View File

@@ -3,7 +3,6 @@ package com.intellij.openapi.vfs.newvfs;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.progress.ProcessCanceledException;
@@ -43,7 +42,7 @@ public final class AsyncEventSupport {
public static void startListening() {
Application app = ApplicationManager.getApplication();
Disposer.register(app, () -> ensureAllEventsProcessed());
Disposer.register(app, AsyncEventSupport::ensureAllEventsProcessed);
app.getMessageBus().connect().subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener() {
@Override
@@ -87,7 +86,7 @@ public final class AsyncEventSupport {
long startNs = System.nanoTime();
boolean canceled = false;
try {
ReadAction.run(() -> ContainerUtil.addIfNotNull(appliers, listener.prepareChange(events)));
ApplicationManager.getApplication().runReadAction(() -> ContainerUtil.addIfNotNull(appliers, listener.prepareChange(events)));
}
catch (ProcessCanceledException e) {
canceled = true;

View File

@@ -10,7 +10,7 @@ import com.intellij.ide.highlighter.ProjectFileType
import com.intellij.openapi.Disposable
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.EDT
import com.intellij.openapi.application.runWriteAction
import com.intellij.openapi.application.writeAction
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service
import com.intellij.openapi.diagnostic.debug
@@ -35,10 +35,16 @@ import com.intellij.project.stateStore
import com.intellij.util.PlatformUtils.isIntelliJ
import com.intellij.util.PlatformUtils.isRider
import com.intellij.workspaceModel.ide.*
import com.intellij.workspaceModel.ide.impl.*
import com.intellij.workspaceModel.ide.impl.GlobalWorkspaceModel
import com.intellij.workspaceModel.ide.impl.WorkspaceModelImpl
import com.intellij.workspaceModel.ide.impl.WorkspaceModelInitialTestContent
import com.intellij.workspaceModel.ide.impl.jps.serialization.JpsProjectEntitiesLoader.createProjectSerializers
import com.intellij.workspaceModel.ide.impl.jpsMetrics
import com.intellij.workspaceModel.ide.legacyBridge.GlobalLibraryTableBridge
import com.intellij.workspaceModel.storage.*
import com.intellij.workspaceModel.storage.DummyParentEntitySource
import com.intellij.workspaceModel.storage.EntitySource
import com.intellij.workspaceModel.storage.MutableEntityStorage
import com.intellij.workspaceModel.storage.VersionedStorageChange
import com.intellij.workspaceModel.storage.bridgeEntities.ModuleEntity
import com.intellij.workspaceModel.storage.url.VirtualFileUrlManager
import io.opentelemetry.api.metrics.Meter
@@ -65,7 +71,7 @@ class JpsProjectModelSynchronizer(private val project: Project) : Disposable {
private val applyLoadedStorageTimeMs: AtomicLong = AtomicLong()
private val saveChangedProjectEntitiesTimeMs: AtomicLong = AtomicLong()
private fun setupOpenTelemetryReporting(meter: Meter): Unit {
private fun setupOpenTelemetryReporting(meter: Meter) {
val jpsLoadProjectToEmptyStorageTimeGauge = meter.gaugeBuilder("jps.load.project.to.empty.storage.ms")
.ofLongs().setDescription("Total time spent in method").buildObserver()
@@ -104,8 +110,9 @@ class JpsProjectModelSynchronizer(private val project: Project) : Disposable {
private var childActivity: Activity? = null
fun needToReloadProjectEntities(): Boolean {
if (StoreReloadManager.getInstance().isReloadBlocked()) return false
if (serializers.get() == null) return false
if (StoreReloadManager.getInstance(project).isReloadBlocked() || serializers.get() == null) {
return false
}
synchronized(incomingChanges) {
return incomingChanges.isNotEmpty()
@@ -115,7 +122,7 @@ class JpsProjectModelSynchronizer(private val project: Project) : Disposable {
suspend fun reloadProjectEntities() {
val start = System.currentTimeMillis()
if (StoreReloadManager.getInstance().isReloadBlocked()) {
if (StoreReloadManager.getInstance(project).isReloadBlocked()) {
LOG.debug("Skip reloading because it's blocked")
return
}
@@ -147,35 +154,33 @@ class JpsProjectModelSynchronizer(private val project: Project) : Disposable {
&& !reloadingResult.unloadedEntityBuilder.hasChanges()
&& !reloadingResult.orphanageBuilder.hasChanges()) return
withContext(Dispatchers.EDT) {
runWriteAction {
val affectedEntityFilter: (EntitySource) -> Boolean = {
it in reloadingResult.affectedSources
|| (it is JpsImportedEntitySource && !it.storedExternally && it.internalFile in reloadingResult.affectedSources)
|| it is DummyParentEntitySource
}
val description = "Reload entities after changes in JPS configuration files"
writeAction {
val affectedEntityFilter: (EntitySource) -> Boolean = {
it in reloadingResult.affectedSources
|| (it is JpsImportedEntitySource && !it.storedExternally && it.internalFile in reloadingResult.affectedSources)
|| it is DummyParentEntitySource
}
val description = "Reload entities after changes in JPS configuration files"
// Update builder of unloaded entities
if (reloadingResult.unloadedEntityBuilder.hasChanges()) {
WorkspaceModel.getInstance(project).updateUnloadedEntities(description) { builder ->
builder.replaceBySource(affectedEntityFilter, reloadingResult.unloadedEntityBuilder.toSnapshot())
}
// Update builder of unloaded entities
if (reloadingResult.unloadedEntityBuilder.hasChanges()) {
WorkspaceModel.getInstance(project).updateUnloadedEntities(description) { builder ->
builder.replaceBySource(affectedEntityFilter, reloadingResult.unloadedEntityBuilder.toSnapshot())
}
}
val unloadedBuilder = MutableEntityStorage.from(WorkspaceModel.getInstance(project).currentSnapshotOfUnloadedEntities)
WorkspaceModel.getInstance(project).updateProjectModel(description) { updater ->
val storage = reloadingResult.builder.toSnapshot()
updater.replaceBySource(affectedEntityFilter, storage)
runAutomaticModuleUnloader(updater, unloadedBuilder)
}
addUnloadedModuleEntities(unloadedBuilder)
sourcesToSave.removeAll(reloadingResult.affectedSources)
val unloadedBuilder = MutableEntityStorage.from(WorkspaceModel.getInstance(project).currentSnapshotOfUnloadedEntities)
WorkspaceModel.getInstance(project).updateProjectModel(description) { updater ->
val storage = reloadingResult.builder.toSnapshot()
updater.replaceBySource(affectedEntityFilter, storage)
runAutomaticModuleUnloader(updater, unloadedBuilder)
}
addUnloadedModuleEntities(unloadedBuilder)
sourcesToSave.removeAll(reloadingResult.affectedSources)
// Update orphanage storage
if (reloadingResult.orphanageBuilder.hasChanges()) {
EntitiesOrphanage.getInstance(project).update { it.addDiff(reloadingResult.orphanageBuilder) }
}
// Update orphanage storage
if (reloadingResult.orphanageBuilder.hasChanges()) {
EntitiesOrphanage.getInstance(project).update { it.addDiff(reloadingResult.orphanageBuilder) }
}
}
@@ -243,7 +248,7 @@ class JpsProjectModelSynchronizer(private val project: Project) : Disposable {
val change = JpsConfigurationFilesChange(addedUrls, removedUrls, changedUrls)
incomingChanges.add(change)
StoreReloadManager.getInstance().scheduleProcessingChangedFiles()
StoreReloadManager.getInstance(project).scheduleProcessingChangedFiles()
}
}
})
@@ -421,7 +426,7 @@ class JpsProjectModelSynchronizer(private val project: Project) : Disposable {
val unloadedModuleSources = WorkspaceModel.getInstance(project).currentSnapshotOfUnloadedEntities.entities(
ModuleEntity::class.java).map { it.entitySource }
synchronized(sourcesToSave) {
//to trigger save for modules.xml
// to trigger save for modules.xml
sourcesToSave.addAll(moduleSources)
sourcesToSave.addAll(unloadedModuleSources)
}

View File

@@ -175,6 +175,7 @@
<applicationService serviceInterface="com.intellij.openapi.components.impl.stores.IComponentStore"
serviceImplementation="com.intellij.configurationStore.ApplicationStoreImpl"/>
<vfs.asyncListener implementation="com.intellij.configurationStore.MyAsyncVfsListener"/>
<applicationService serviceInterface="com.intellij.openapi.components.PathMacroManager"
serviceImplementation="com.intellij.configurationStore.ApplicationPathMacroManager"/>
@@ -1219,9 +1220,8 @@
<registryKey key="run.anything.context.recent.directory.number" defaultValue="5"
description="Defines storing Run Anything context combobox directories number."/>
<applicationService serviceInterface="com.intellij.configurationStore.StoreReloadManager"
serviceImplementation="com.intellij.configurationStore.StoreReloadManagerImpl"/>
<virtualFileManagerListener implementation="com.intellij.configurationStore.StoreReloadManagerImpl$MyVirtualFileManagerListener"/>
<projectService serviceInterface="com.intellij.configurationStore.StoreReloadManager"
serviceImplementation="com.intellij.configurationStore.StoreReloadManagerImpl"/>
<applicationService serviceInterface="com.intellij.ide.lightEdit.LightEditService"
serviceImplementation="com.intellij.ide.lightEdit.LightEditServiceImpl"/>

View File

@@ -51,7 +51,7 @@ public class NonProjectFileAccessTest extends HeavyFileEditorManagerTestCase {
EditorNotifications notifications = new EditorNotificationsImpl(project, project.getCoroutineScope());
ServiceContainerUtil.replaceService(project, EditorNotifications.class, notifications, getTestRootDisposable());
NonProjectFileWritingAccessProvider.enableChecksInTests(project);
StoreReloadManager.getInstance().blockReloadingProjectOnExternalChanges();
StoreReloadManager.Companion.getInstance(project).blockReloadingProjectOnExternalChanges();
}
@Override
@@ -75,7 +75,7 @@ public class NonProjectFileAccessTest extends HeavyFileEditorManagerTestCase {
}
finally {
super.tearDown();
StoreReloadManager.getInstance().unblockReloadingProjectOnExternalChanges(); // unblock only after project is disposed;
StoreReloadManager.Companion.getInstance(getProject()).unblockReloadingProjectOnExternalChanges(); // unblock only after project is disposed;
}
}

View File

@@ -1,15 +1,11 @@
// 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 java.io.IOException
interface SaveSession : StorageManagerFileWriteRequestor {
@Throws(IOException::class)
fun save()
}
interface SaveSessionProducer : StorageManagerFileWriteRequestor {
@Throws(IOException::class)
fun setState(component: Any?, componentName: String, state: Any?)
/**
@@ -19,6 +15,6 @@ interface SaveSessionProducer : StorageManagerFileWriteRequestor {
}
/**
* A marker interface for [FileUndoProvider] to not process this file change event.
* A marker interface for to not process this file change event.
*/
interface StorageManagerFileWriteRequestor

View File

@@ -48,8 +48,5 @@ interface StorageCreator {
// better to reduce message bus usage
fun isFireStorageFileChangedEvent(event: VFileEvent): Boolean {
// ignore VFilePropertyChangeEvent because doesn't affect content
return when (event) {
is VFilePropertyChangeEvent -> false
else -> event.requestor !is StorageManagerFileWriteRequestor
}
return event !is VFilePropertyChangeEvent && event.requestor !is StorageManagerFileWriteRequestor
}

View File

@@ -14,7 +14,7 @@ import java.util.function.Consumer
// todo rewrite PlatformTestUtil to kotlin
internal fun saveProject(project: Project, forceSavingAllSettings: Boolean = false) {
runUnderModalProgressIfIsEdt {
StoreReloadManager.getInstance().reloadChangedStorageFiles()
StoreReloadManager.getInstance(project).reloadChangedStorageFiles()
project.stateStore.save(forceSavingAllSettings = forceSavingAllSettings)
}
}

View File

@@ -17,5 +17,5 @@ suspend fun copyFilesAndReloadProject(project: Project, fromDir: Path) {
FileUtil.copyDir(fromDir.toFile(), base.toFile())
VfsUtil.markDirtyAndRefresh(false, true, true, projectDir)
StoreReloadManager.getInstance().reloadChangedStorageFiles()
StoreReloadManager.getInstance(project).reloadChangedStorageFiles()
}

View File

@@ -2,7 +2,6 @@
package com.intellij.util.io
import com.intellij.openapi.util.io.NioFiles
import java.io.File
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
@@ -14,6 +13,7 @@ import java.nio.file.attribute.BasicFileAttributes
import java.nio.file.attribute.FileTime
import java.util.*
import kotlin.io.path.exists
import kotlin.io.path.invariantSeparatorsPathString
@Suppress("DeprecatedCallableAddReplaceWith") // ReplaceWith does not work
@Deprecated(message = "Use kotlin.io.path.exists", level = DeprecationLevel.ERROR)
@@ -103,7 +103,7 @@ fun Path.deleteChildrenStartingWith(prefix: String) {
fun Path.lastModified(): FileTime = Files.getLastModifiedTime(this)
val Path.systemIndependentPath: String
get() = toString().replace(File.separatorChar, '/')
get() = invariantSeparatorsPathString
@Throws(IOException::class)
fun Path.readBytes(): ByteArray = Files.readAllBytes(this)

View File

@@ -58,19 +58,21 @@ public class VcsFreezingProcess {
LOG.debug("finished.");
}
private static void saveAndBlockInAwt() {
private void saveAndBlockInAwt() {
ApplicationManager.getApplication().invokeAndWait(() -> {
StoreReloadManager.getInstance().blockReloadingProjectOnExternalChanges();
StoreReloadManager.Companion.getInstance(myProject).blockReloadingProjectOnExternalChanges();
FileDocumentManager.getInstance().saveAllDocuments();
SaveAndSyncHandler saveAndSyncHandler = SaveAndSyncHandler.getInstance();
saveAndSyncHandler.blockSaveOnFrameDeactivation();
saveAndSyncHandler.blockSyncOnFrameActivation();
});
}
private static void unblockInAwt() {
private void unblockInAwt() {
ApplicationManager.getApplication().invokeAndWait(() -> {
StoreReloadManager.getInstance().unblockReloadingProjectOnExternalChanges();
StoreReloadManager.Companion.getInstance(myProject).unblockReloadingProjectOnExternalChanges();
SaveAndSyncHandler saveAndSyncHandler = SaveAndSyncHandler.getInstance();
saveAndSyncHandler.unblockSaveOnFrameDeactivation();
saveAndSyncHandler.unblockSyncOnFrameActivation();

View File

@@ -60,14 +60,12 @@ import javax.swing.table.AbstractTableModel
import javax.swing.tree.DefaultMutableTreeNode
import javax.swing.tree.TreeNode
open class MultipleFileMergeDialog(
private val project: Project?,
files: List<VirtualFile>,
private val mergeProvider: MergeProvider,
private val mergeDialogCustomizer: MergeDialogCustomizer
) : DialogWrapper(project) {
private var unresolvedFiles = files.toMutableList()
private val mergeSession = (mergeProvider as? MergeProvider2)?.createMergeSession(files)
val processedFiles: MutableList<VirtualFile> = mutableListOf()
@@ -95,7 +93,7 @@ open class MultipleFileMergeDialog(
}
init {
StoreReloadManager.getInstance().blockReloadingProjectOnExternalChanges()
project?.let { StoreReloadManager.getInstance(project).blockReloadingProjectOnExternalChanges() }
title = mergeDialogCustomizer.getMultipleFileDialogTitle()
virtualFileRenderer.font = UIUtil.getListFont()
@@ -169,7 +167,7 @@ open class MultipleFileMergeDialog(
showMergeDialog()
}
}
mergeAction.putValue(DEFAULT_ACTION, java.lang.Boolean.TRUE)
mergeAction.putValue(DEFAULT_ACTION, true)
mergeButton = createJButtonForAction(mergeAction)
cell(mergeButton)
.align(AlignX.FILL)
@@ -261,7 +259,7 @@ open class MultipleFileMergeDialog(
}
override fun dispose() {
StoreReloadManager.getInstance().unblockReloadingProjectOnExternalChanges()
project?.let { StoreReloadManager.getInstance(project).unblockReloadingProjectOnExternalChanges() }
super.dispose()
}

View File

@@ -339,7 +339,9 @@ public abstract class AbstractCommonUpdateAction extends AbstractVcsAction {
}
private void runImpl() {
StoreReloadManager.getInstance().blockReloadingProjectOnExternalChanges();
if (myProject != null) {
StoreReloadManager.Companion.getInstance(myProject).blockReloadingProjectOnExternalChanges();
}
myProjectLevelVcsManager.startBackgroundVcsOperation();
myBefore = LocalHistory.getInstance().putSystemLabel(myProject, VcsBundle.message("update.label.before.update"));
@@ -497,7 +499,7 @@ public abstract class AbstractCommonUpdateAction extends AbstractVcsAction {
private void onSuccessImpl(final boolean wasCanceled) {
if (!myProject.isOpen() || myProject.isDisposed()) {
StoreReloadManager.getInstance().unblockReloadingProjectOnExternalChanges();
StoreReloadManager.Companion.getInstance(myProject).unblockReloadingProjectOnExternalChanges();
LocalHistory.getInstance().putSystemLabel(myProject, VcsBundle.message("local.history.update.from.vcs")); // TODO check why this label is needed
return;
}
@@ -538,7 +540,7 @@ public abstract class AbstractCommonUpdateAction extends AbstractVcsAction {
final boolean updateSuccess = !someSessionWasCancelled && myGroupedExceptions.isEmpty();
if (myProject.isDisposed()) {
StoreReloadManager.getInstance().unblockReloadingProjectOnExternalChanges();
StoreReloadManager.Companion.getInstance(myProject).unblockReloadingProjectOnExternalChanges();
return;
}
@@ -589,7 +591,7 @@ public abstract class AbstractCommonUpdateAction extends AbstractVcsAction {
}
StoreReloadManager.getInstance().unblockReloadingProjectOnExternalChanges();
StoreReloadManager.Companion.getInstance(myProject).unblockReloadingProjectOnExternalChanges();
if (continueChainFinal && updateSuccess) {
if (!noMerged) {

View File

@@ -6,6 +6,7 @@ import com.intellij.configurationStore.*
import com.intellij.openapi.components.BaseState
import com.intellij.openapi.components.PersistentStateComponent
import com.intellij.openapi.components.StateStorage
import com.intellij.openapi.components.stateStore
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.project.Project
import com.intellij.util.ReflectionUtil
@@ -22,7 +23,7 @@ private class MyProjectStore(project: Project) : ProjectWithModulesStoreImpl(pro
fun configurationFileChanged() {
if (storages.isNotEmpty()) {
StoreReloadManager.getInstance().storageFilesChanged(mapOf(project to storages.values.toList()))
StoreReloadManager.getInstance(project).storageFilesChanged(project.stateStore, storages.values.toList())
}
}

View File

@@ -72,9 +72,9 @@ private fun deleteRepository(icsManager: IcsManager) {
runBlockingModalWithRawProgressReporter(ModalTaskOwner.guess(), IcsBundle.message("progress.syncing.before.deleting.repository")) {
val repositoryManager = icsManager.repositoryManager
// attempt to fetch, merge and push to ensure that latest changes in the deleted user repository will be not lost
// Attempt to fetch, merge and push to ensure that the latest changes in the deleted user repository will be not lost
// yes, - delete repository doesn't mean "AAA, delete it, delete". It means just that user doesn't need it at this moment.
// It is user responsibility later to delete git repository or do whatever user want. Our responsibility is to not loose user changes.
// It is user responsibility later to delete git repository or do whatever user wants. Our responsibility is to not lose user changes.
if (!repositoryManager.canCommit()) {
LOG.info("Commit on repository delete skipped: repository is not committable")
return@runBlockingModalWithRawProgressReporter
@@ -83,7 +83,7 @@ private fun deleteRepository(icsManager: IcsManager) {
catchAndLog(asWarning = true) {
val updater = repositoryManager.fetch()
ensureActive()
// ignore result, we don't need to apply it
// ignore a result, we don't need to apply it
updater.merge()
ensureActive()
if (!updater.definitelySkipPush) {

View File

@@ -95,7 +95,9 @@ public class SvnIntegrateChangesTask extends Task.Backgroundable {
myHandler.setProgressIndicator(ProgressManager.getInstance().getProgressIndicator());
myResolveWorker = new ResolveWorker(myInfo.isUnderProjectRoot(), myProject);
StoreReloadManager.getInstance().blockReloadingProjectOnExternalChanges();
if (myProject != null) {
StoreReloadManager.Companion.getInstance(myProject).blockReloadingProjectOnExternalChanges();
}
myProjectLevelVcsManager.startBackgroundVcsOperation();
try {
@@ -158,7 +160,9 @@ public class SvnIntegrateChangesTask extends Task.Backgroundable {
afterExecution(wasCancelled);
}
finally {
StoreReloadManager.getInstance().unblockReloadingProjectOnExternalChanges();
if (myProject != null) {
StoreReloadManager.Companion.getInstance(myProject).unblockReloadingProjectOnExternalChanges();
}
}
});
}