mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
deprecate projectComponentsInitialized in favour of white-listed EP
Another step to protect loading: `ProjectLifecycleListener.projectComponentsInitialized` is deprecated in favour of a new white-listed EP `ProjectServiceContainerInitializedListener`. As for `ProjectServiceContainerCustomizer` (that was introduced for legacy project model), new EP can be extended only by core plugin (runtime error for non-core). Message bus must be not used for any control events, that’s why EP is used here (as for any such solutions in our new code). Even more — EP is a more simpler and suitable here. EP allows you to control order of execution — yes, if you want specific order, it means that your code is bad. But not possible for now to fix RunManager. GitOrigin-RevId: 2493a14678d8604193dfff84008882d5ec4d2a24
This commit is contained in:
committed by
intellij-monorepo-bot
parent
7b3fba15f8
commit
a0e751cc6e
@@ -1,7 +1,8 @@
|
||||
# 16
|
||||
|
||||
* add `run manager initialization`
|
||||
* add `projectComponentsInitialized event handling`
|
||||
* add `RunManager initialization`
|
||||
* add `projectComponentCreated event handling`
|
||||
* add `projectComponentCreated`
|
||||
|
||||
## 15
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// 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.
|
||||
// Copyright 2000-2020 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.diagnostic.startUpPerformanceReporter
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator
|
||||
@@ -40,7 +40,7 @@ class StartUpPerformanceReporter : StartupActivity, StartUpPerformanceService {
|
||||
companion object {
|
||||
internal val LOG = logger<StartUpMeasurer>()
|
||||
|
||||
internal const val VERSION = "15"
|
||||
internal const val VERSION = "16"
|
||||
|
||||
internal fun sortItems(items: MutableList<ActivityImpl>) {
|
||||
items.sortWith(Comparator { o1, o2 ->
|
||||
|
||||
+10
-18
@@ -1,32 +1,24 @@
|
||||
// Copyright 2000-2020 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.execution.impl
|
||||
|
||||
import com.intellij.diagnostic.runActivity
|
||||
import com.intellij.execution.IS_RUN_MANAGER_INITIALIZED
|
||||
import com.intellij.execution.RunManager
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.project.impl.ProjectLifecycleListener
|
||||
import com.intellij.openapi.project.ProjectServiceContainerInitializedListener
|
||||
|
||||
internal class ProjectRunConfigurationInitializer(project: Project) {
|
||||
init {
|
||||
val connection = project.messageBus.connect()
|
||||
connection.subscribe(ProjectLifecycleListener.TOPIC, object : ProjectLifecycleListener {
|
||||
override fun projectComponentsInitialized(eventProject: Project) {
|
||||
if (project === eventProject) {
|
||||
requestLoadWorkspaceAndProjectRunConfiguration(project)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun requestLoadWorkspaceAndProjectRunConfiguration(project: Project) {
|
||||
private class ProjectRunConfigurationInitializer : ProjectServiceContainerInitializedListener {
|
||||
override fun serviceCreated(project: Project) {
|
||||
if (IS_RUN_MANAGER_INITIALIZED.get(project) == true) {
|
||||
return
|
||||
}
|
||||
|
||||
IS_RUN_MANAGER_INITIALIZED.set(project, true)
|
||||
// we must not fire beginUpdate here, because message bus will fire queued parent message bus messages (and, so, SOE may occur because all other projectOpened will be processed before us)
|
||||
// simply, you should not listen changes until project opened
|
||||
project.service<RunManager>()
|
||||
runActivity("RunManager initialization") {
|
||||
IS_RUN_MANAGER_INITIALIZED.set(project, true)
|
||||
// we must not fire beginUpdate here, because message bus will fire queued parent message bus messages (and, so, SOE may occur because all other projectOpened will be processed before us)
|
||||
// simply, you should not listen changes until project opened
|
||||
project.service<RunManager>()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@
|
||||
package com.intellij.execution
|
||||
|
||||
import com.intellij.execution.configurations.*
|
||||
import com.intellij.openapi.components.ServiceManager
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.Key
|
||||
@@ -24,7 +23,7 @@ abstract class RunManager {
|
||||
// https://gist.github.com/develar/5bcf39b3f0ec08f507ec112d73375f2b
|
||||
LOG.debug("Must be not called before project components initialized")
|
||||
}
|
||||
return ServiceManager.getService(project, RunManager::class.java)
|
||||
return project.getService(RunManager::class.java)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
|
||||
+19
-17
@@ -1,4 +1,4 @@
|
||||
// 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.
|
||||
// Copyright 2000-2020 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.module.impl;
|
||||
|
||||
import com.intellij.ProjectTopics;
|
||||
@@ -11,11 +11,12 @@ import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.components.State;
|
||||
import com.intellij.openapi.components.Storage;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleManager;
|
||||
import com.intellij.openapi.module.ModuleType;
|
||||
import com.intellij.openapi.module.UnknownModuleType;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectBundle;
|
||||
import com.intellij.openapi.project.impl.ProjectLifecycleListener;
|
||||
import com.intellij.openapi.project.ProjectServiceContainerInitializedListener;
|
||||
import com.intellij.openapi.vfs.VirtualFileManager;
|
||||
import com.intellij.util.messages.MessageBusConnection;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -25,9 +26,6 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
@State(
|
||||
name = ModuleManagerImpl.COMPONENT_NAME,
|
||||
storages = @Storage("modules.xml"),
|
||||
@@ -48,21 +46,25 @@ public class ModuleManagerComponent extends ModuleManagerImpl {
|
||||
return;
|
||||
}
|
||||
|
||||
myMessageBusConnection.subscribe(ProjectLifecycleListener.TOPIC, new ProjectLifecycleListener() {
|
||||
@Override
|
||||
public void projectComponentsInitialized(@NotNull final Project project) {
|
||||
if (project != myProject) return;
|
||||
|
||||
Activity activity = StartUpMeasurer.startMainActivity("module loading");
|
||||
loadModules(myModuleModel);
|
||||
activity.end();
|
||||
activity.setDescription("module count: " + myModuleModel.getModules().length);
|
||||
}
|
||||
});
|
||||
|
||||
myMessageBusConnection.subscribe(VirtualFileManager.VFS_CHANGES, new ModuleFileListener(this));
|
||||
}
|
||||
|
||||
static class MyProjectServiceContainerInitializedListener implements ProjectServiceContainerInitializedListener {
|
||||
@Override
|
||||
public void serviceCreated(@NotNull Project project) {
|
||||
Activity activity = StartUpMeasurer.startMainActivity("module loading");
|
||||
ModuleManager moduleManager = getInstance(project);
|
||||
if (!(moduleManager instanceof ModuleManagerImpl)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ModuleManagerImpl manager = (ModuleManagerImpl)moduleManager;
|
||||
manager.loadModules(manager.myModuleModel);
|
||||
activity.end();
|
||||
activity.setDescription("module count: " + manager.myModuleModel.getModules().length);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void unloadNewlyAddedModulesIfPossible(@NotNull Set<ModulePath> modulesToLoad, @NotNull List<UnloadedModuleDescriptionImpl> modulesToUnload) {
|
||||
UnloadedModulesListChange change = AutomaticModuleUnloader.getInstance(myProject).processNewModules(modulesToLoad, modulesToUnload);
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
// 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.
|
||||
// Copyright 2000-2020 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.ide;
|
||||
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
/**
|
||||
* Use extension point {@code com.intellij.applicationInitializedListener} to register listener.
|
||||
@@ -9,6 +10,7 @@ import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
* <p>
|
||||
* Not part of {@link ApplicationLoadListener} to avoid class loading before application initialization.
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
public interface ApplicationInitializedListener {
|
||||
/**
|
||||
* Invoked when all application level components are initialized in the same thread where components are initializing (EDT is not guaranteed).
|
||||
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
// 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.project
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.extensions.impl.ExtensionPointImpl
|
||||
import com.intellij.openapi.extensions.impl.ExtensionsAreaImpl
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
/**
|
||||
* Usage requires IJ Platform team approval (including plugin into white-list).
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
interface ProjectServiceContainerCustomizer {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun getEp(): ExtensionPointImpl<ProjectServiceContainerCustomizer> {
|
||||
return (ApplicationManager.getApplication().extensionArea as ExtensionsAreaImpl)
|
||||
.getExtensionPoint("com.intellij.projectServiceContainerCustomizer")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked after implementation classes for project's components were determined (and loaded),
|
||||
* but before components are instantiated.
|
||||
*/
|
||||
fun serviceContainerInitialized(project: Project)
|
||||
}
|
||||
+5
-1
@@ -1,4 +1,4 @@
|
||||
// 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.
|
||||
// Copyright 2000-2020 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.project.impl;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
@@ -13,6 +13,10 @@ import org.jetbrains.annotations.NotNull;
|
||||
public interface ProjectLifecycleListener {
|
||||
Topic<ProjectLifecycleListener> TOPIC = Topic.create("Various stages of project lifecycle notifications", ProjectLifecycleListener.class);
|
||||
|
||||
/**
|
||||
* @deprecated Do not use.
|
||||
*/
|
||||
@Deprecated
|
||||
default void projectComponentsInitialized(@NotNull Project project) {
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.openapi.components.ComponentConfig;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.project.ProjectLoadHelper;
|
||||
import com.intellij.openapi.project.impl.ProjectImpl;
|
||||
import com.intellij.openapi.project.impl.ProjectLifecycleListener;
|
||||
import com.intellij.openapi.roots.ProjectFileIndex;
|
||||
@@ -21,8 +22,7 @@ import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Set;
|
||||
|
||||
class LightEditProject extends ProjectImpl {
|
||||
|
||||
final class LightEditProject extends ProjectImpl {
|
||||
private static final Logger LOG = Logger.getInstance(LightEditProject.class);
|
||||
private static final String NAME = "LightEditProject";
|
||||
private static final Set<String> ALLOWED_CLASSES = ContainerUtil.newHashSet(
|
||||
@@ -38,7 +38,8 @@ class LightEditProject extends ProjectImpl {
|
||||
|
||||
private LightEditProject(@NotNull Path projectPath) {
|
||||
super(projectPath, NAME);
|
||||
registerComponents();
|
||||
|
||||
ProjectLoadHelper.registerComponents(this);
|
||||
customizeRegisteredComponents();
|
||||
getStateStore().setPath(projectPath, false, null);
|
||||
init(null);
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
package com.intellij.openapi.project.impl;
|
||||
|
||||
import com.intellij.configurationStore.StoreUtil;
|
||||
import com.intellij.diagnostic.Activity;
|
||||
import com.intellij.diagnostic.StartUpMeasurer;
|
||||
import com.intellij.ide.plugins.ContainerDescriptor;
|
||||
import com.intellij.ide.plugins.IdeaPluginDescriptorImpl;
|
||||
import com.intellij.ide.plugins.PluginManagerCore;
|
||||
@@ -22,11 +20,10 @@ import com.intellij.openapi.components.impl.stores.IProjectStore;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.module.ModuleManager;
|
||||
import com.intellij.openapi.module.impl.ModuleManagerImpl;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectLoadHelper;
|
||||
import com.intellij.openapi.project.ProjectManager;
|
||||
import com.intellij.openapi.project.ProjectServiceContainerCustomizer;
|
||||
import com.intellij.openapi.project.ex.ProjectEx;
|
||||
import com.intellij.openapi.project.ex.ProjectManagerEx;
|
||||
import com.intellij.openapi.startup.StartupManager;
|
||||
@@ -257,37 +254,6 @@ public class ProjectImpl extends PlatformComponentManagerImpl implements Project
|
||||
return workspaceFilePath == null ? null : LocalFileSystem.getInstance().findFileByPath(workspaceFilePath);
|
||||
}
|
||||
|
||||
public final void registerComponents() {
|
||||
String activityNamePrefix = activityNamePrefix();
|
||||
Activity activity = (activityNamePrefix == null || !StartUpMeasurer.isEnabled()) ? null : StartUpMeasurer.startMainActivity(activityNamePrefix + StartUpMeasurer.Activities.REGISTER_COMPONENTS_SUFFIX);
|
||||
// at this point of time plugins are already loaded by application - no need to pass indicator to getLoadedPlugins call
|
||||
//noinspection unchecked
|
||||
registerComponents((List<IdeaPluginDescriptorImpl>)PluginManagerCore.getLoadedPlugins(), false);
|
||||
if (activity != null) {
|
||||
activity = activity.endAndStart("projectComponentRegistered");
|
||||
}
|
||||
|
||||
ProjectServiceContainerCustomizer.getEp().processWithPluginDescriptor((customizer, pluginDescriptor) -> {
|
||||
if (pluginDescriptor.getPluginId() != PluginManagerCore.CORE_ID) {
|
||||
LOG.error("Plugin " + pluginDescriptor + " is not approved to add ProjectServiceContainerCustomizer");
|
||||
}
|
||||
|
||||
try {
|
||||
customizer.serviceContainerInitialized(this);
|
||||
}
|
||||
catch (ProcessCanceledException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
});
|
||||
|
||||
if (activity != null) {
|
||||
activity.end();
|
||||
}
|
||||
}
|
||||
|
||||
public void init(@Nullable ProgressIndicator indicator) {
|
||||
Application application = ApplicationManager.getApplication();
|
||||
|
||||
@@ -311,7 +277,8 @@ public class ProjectImpl extends PlatformComponentManagerImpl implements Project
|
||||
if (myName == null) {
|
||||
myName = getStateStore().getProjectName();
|
||||
}
|
||||
application.getMessageBus().syncPublisher(ProjectLifecycleListener.TOPIC).projectComponentsInitialized(this);
|
||||
|
||||
ProjectLoadHelper.notifyThatComponentCreated(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -308,7 +308,7 @@ public class ProjectManagerImpl extends ProjectManagerEx implements Disposable {
|
||||
|
||||
boolean succeed = false;
|
||||
try {
|
||||
project.registerComponents();
|
||||
ProjectLoadHelper.registerComponents(project);
|
||||
project.getStateStore().setPath(file, isRefreshVfsNeeded, template);
|
||||
project.init(indicator);
|
||||
succeed = true;
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
// Copyright 2000-2020 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.project
|
||||
|
||||
import com.intellij.diagnostic.Activity
|
||||
import com.intellij.diagnostic.PluginException
|
||||
import com.intellij.diagnostic.StartUpMeasurer
|
||||
import com.intellij.diagnostic.StartUpMeasurer.Activities
|
||||
import com.intellij.ide.plugins.IdeaPluginDescriptorImpl
|
||||
import com.intellij.ide.plugins.PluginManagerCore
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.diagnostic.logger
|
||||
import com.intellij.openapi.extensions.impl.ExtensionPointImpl
|
||||
import com.intellij.openapi.extensions.impl.ExtensionsAreaImpl
|
||||
import com.intellij.openapi.progress.ProcessCanceledException
|
||||
import com.intellij.openapi.project.impl.ProjectImpl
|
||||
import com.intellij.openapi.project.impl.ProjectLifecycleListener
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
// Code maybe located in a ProjectImpl, but it is not possible due to non-technical reasons to convert ProjectImpl into modern language.
|
||||
// Wrap into class as it is not possible to use internal modifier for top-level functions from Java (but we have to reduce scope).
|
||||
@ApiStatus.Internal
|
||||
internal class ProjectLoadHelper {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun registerComponents(project: ProjectImpl) {
|
||||
var activity = createActivity(project) { "project ${Activities.REGISTER_COMPONENTS_SUFFIX}" }
|
||||
// at this point of time plugins are already loaded by application - no need to pass indicator to getLoadedPlugins call
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
project.registerComponents(PluginManagerCore.getLoadedPlugins() as List<IdeaPluginDescriptorImpl>, notifyListeners = false)
|
||||
|
||||
activity = activity?.endAndStart("projectComponentRegistered")
|
||||
runHandler(ProjectServiceContainerCustomizer.getEp()) {
|
||||
it.serviceRegistered(project)
|
||||
}
|
||||
activity?.end()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun notifyThatComponentCreated(project: ProjectImpl) {
|
||||
var activity = createActivity(project) { "projectComponentCreated event handling" }
|
||||
val app = ApplicationManager.getApplication()
|
||||
@Suppress("DEPRECATION")
|
||||
app.messageBus.syncPublisher(ProjectLifecycleListener.TOPIC).projectComponentsInitialized(project)
|
||||
|
||||
activity = activity?.endAndStart("projectComponentCreated")
|
||||
runHandler((app.extensionArea as ExtensionsAreaImpl).getExtensionPoint<ProjectServiceContainerInitializedListener>("com.intellij.projectServiceContainerInitializedListener")) {
|
||||
it.serviceCreated(project)
|
||||
}
|
||||
activity?.end()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val LOG = logger<ProjectImpl>()
|
||||
|
||||
private inline fun createActivity(project: ProjectImpl, message: () -> String): Activity? {
|
||||
return if (project.isDefault || !StartUpMeasurer.isEnabled()) null else StartUpMeasurer.startActivity(message())
|
||||
}
|
||||
|
||||
private inline fun <T : Any> runHandler(ep: ExtensionPointImpl<T>, crossinline executor: (T) -> Unit) {
|
||||
ep.processWithPluginDescriptor { handler, pluginDescriptor ->
|
||||
if (pluginDescriptor.pluginId != PluginManagerCore.CORE_ID) {
|
||||
LOG.error(PluginException("Plugin $pluginDescriptor is not approved to add ${ep.name}", pluginDescriptor.pluginId))
|
||||
}
|
||||
|
||||
try {
|
||||
executor(handler)
|
||||
}
|
||||
catch (e: ProcessCanceledException) {
|
||||
throw e
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
LOG.error(PluginException(e, pluginDescriptor.pluginId))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Usage requires IJ Platform team approval (including plugin into white-list).
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
interface ProjectServiceContainerCustomizer {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun getEp(): ExtensionPointImpl<ProjectServiceContainerCustomizer> {
|
||||
return (ApplicationManager.getApplication().extensionArea as ExtensionsAreaImpl)
|
||||
.getExtensionPoint("com.intellij.projectServiceContainerCustomizer")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked after implementation classes for project's components were determined (and loaded),
|
||||
* but before components are instantiated.
|
||||
*/
|
||||
fun serviceRegistered(project: Project)
|
||||
}
|
||||
|
||||
/**
|
||||
* Usage requires IJ Platform team approval (including plugin into white-list).
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
interface ProjectServiceContainerInitializedListener {
|
||||
/**
|
||||
* Invoked after implementation classes for project's components were determined (and loaded),
|
||||
* but before components are instantiated.
|
||||
*/
|
||||
fun serviceCreated(project: Project)
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
<idea-plugin>
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<projectServiceContainerInitializedListener implementation="com.intellij.openapi.module.impl.ModuleManagerComponent$MyProjectServiceContainerInitializedListener" order="first"/>
|
||||
|
||||
<applicationService serviceInterface="com.intellij.openapi.project.impl.ProjectStoreFactory"
|
||||
serviceImplementation="com.intellij.configurationStore.PlatformLangProjectStoreFactory"
|
||||
overrides="true"/>
|
||||
|
||||
@@ -346,7 +346,9 @@
|
||||
<extensionPoint name="editorFactoryMouseMotionListener" interface="com.intellij.openapi.editor.event.EditorMouseMotionListener" dynamic="true"/>
|
||||
|
||||
<extensionPoint name="projectCloseHandler" interface="com.intellij.openapi.project.ProjectCloseHandler"/>
|
||||
<extensionPoint name="projectServiceContainerCustomizer" interface="com.intellij.openapi.project.ProjectServiceContainerCustomizer"/>
|
||||
|
||||
<extensionPoint name="projectServiceContainerCustomizer" interface="com.intellij.openapi.project.ProjectServiceContainerCustomizer" dynamic="true"/>
|
||||
<extensionPoint name="projectServiceContainerInitializedListener" interface="com.intellij.openapi.project.ProjectServiceContainerInitializedListener" dynamic="true"/>
|
||||
|
||||
<extensionPoint name="actionConfigurationCustomizer" interface="com.intellij.openapi.actionSystem.impl.ActionConfigurationCustomizer" dynamic="false"/>
|
||||
|
||||
|
||||
@@ -533,6 +533,7 @@
|
||||
|
||||
<projectService serviceInterface="com.intellij.execution.RunManager" serviceImplementation="com.intellij.execution.impl.RunManagerImpl"/>
|
||||
<projectService serviceImplementation="com.intellij.execution.impl.IprRunManagerImpl"/>
|
||||
<projectServiceContainerInitializedListener implementation="com.intellij.execution.impl.ProjectRunConfigurationInitializer" order="last"/>
|
||||
|
||||
<fileEditorProvider implementation="com.intellij.openapi.fileEditor.impl.http.HttpFileEditorProvider"/>
|
||||
<editorActionHandler action="EditorEscape" implementationClass="com.intellij.codeInsight.hint.EscapeHandler" id="hide-hints"/>
|
||||
|
||||
@@ -21,10 +21,6 @@
|
||||
<implementation-class>com.intellij.psi.search.scope.packageSet.UpdatingScopeOnProjectStructureChangeListener</implementation-class>
|
||||
</component>
|
||||
|
||||
<component>
|
||||
<implementation-class>com.intellij.execution.impl.ProjectRunConfigurationInitializer</implementation-class>
|
||||
</component>
|
||||
|
||||
<component>
|
||||
<interface-class>com.intellij.openapi.fileEditor.FileEditorManager</interface-class>
|
||||
<implementation-class>com.intellij.openapi.fileEditor.impl.PsiAwareFileEditorManagerImpl</implementation-class>
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
|
||||
<cachesInvalidator implementation="com.intellij.workspace.ide.WorkspaceModelCachesInvalidator"/>
|
||||
|
||||
<projectServiceContainerCustomizer
|
||||
implementation="com.intellij.workspace.legacyBridge.intellij.LegacyBridgeProjectLifecycleListener"/>
|
||||
<projectServiceContainerCustomizer implementation="com.intellij.workspace.legacyBridge.intellij.LegacyBridgeProjectLifecycleListener"/>
|
||||
<projectServiceContainerInitializedListener implementation="com.intellij.workspace.legacyBridge.intellij.LegacyBridgeModuleManagerComponent$MyProjectServiceContainerInitializedListener"/>
|
||||
|
||||
<applicationService serviceInterface="com.intellij.configurationStore.StoreReloadManager"
|
||||
serviceImplementation="com.intellij.workspace.jps.LegacyBridgeStoreReloadManager"
|
||||
|
||||
+70
-63
@@ -1,3 +1,4 @@
|
||||
// Copyright 2000-2020 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.workspace.legacyBridge.intellij
|
||||
|
||||
import com.intellij.ProjectTopics
|
||||
@@ -8,7 +9,6 @@ import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.PathManager
|
||||
import com.intellij.openapi.application.runWriteAction
|
||||
import com.intellij.openapi.components.ProjectComponent
|
||||
import com.intellij.openapi.components.stateStore
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.diagnostic.logger
|
||||
@@ -16,7 +16,9 @@ import com.intellij.openapi.diagnostic.runAndLogException
|
||||
import com.intellij.openapi.module.*
|
||||
import com.intellij.openapi.module.impl.*
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.project.impl.ProjectLifecycleListener
|
||||
import com.intellij.openapi.project.ProjectManager
|
||||
import com.intellij.openapi.project.ProjectManagerListener
|
||||
import com.intellij.openapi.project.ProjectServiceContainerInitializedListener
|
||||
import com.intellij.openapi.roots.ModuleRootManager
|
||||
import com.intellij.openapi.roots.ex.ProjectRootManagerEx
|
||||
import com.intellij.openapi.util.Disposer
|
||||
@@ -38,58 +40,61 @@ import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.ConcurrentMap
|
||||
|
||||
@Suppress("ComponentNotRegistered")
|
||||
class LegacyBridgeModuleManagerComponent(private val project: Project) : ModuleManagerEx(), ProjectComponent, Disposable {
|
||||
|
||||
class LegacyBridgeModuleManagerComponent(private val project: Project) : ModuleManagerEx(), Disposable {
|
||||
val outOfTreeModulesPath: String =
|
||||
FileUtilRt.toSystemIndependentName(File(PathManager.getTempPath(), "outOfTreeProjectModules-${project.locationHash}").path)
|
||||
|
||||
private val LOG = Logger.getInstance(javaClass)
|
||||
|
||||
private val idToModule: ConcurrentMap<ModuleId, LegacyBridgeModule> = ConcurrentHashMap()
|
||||
internal val unloadedModules: MutableMap<String, UnloadedModuleDescriptionImpl> = mutableMapOf()
|
||||
private val newModuleInstances = mutableMapOf<ModuleId, LegacyBridgeModule>()
|
||||
|
||||
override fun dispose() {
|
||||
val modules = modulesMap.values.toList()
|
||||
modulesMap.clear()
|
||||
val modules = idToModule.values.toList()
|
||||
idToModule.clear()
|
||||
|
||||
for (module in modules) {
|
||||
Disposer.dispose(module)
|
||||
}
|
||||
}
|
||||
|
||||
private val modulesMap: ConcurrentMap<ModuleId, LegacyBridgeModule> = ConcurrentHashMap()
|
||||
internal val unloadedModules: MutableMap<String, UnloadedModuleDescriptionImpl> = mutableMapOf()
|
||||
private val newModuleInstances = mutableMapOf<ModuleId, LegacyBridgeModule>()
|
||||
internal class MyProjectServiceContainerInitializedListener : ProjectServiceContainerInitializedListener {
|
||||
override fun serviceCreated(project: Project) {
|
||||
val manager = ModuleManagerComponent.getInstance(project) as? LegacyBridgeModuleManagerComponent ?: return
|
||||
|
||||
@ApiStatus.Internal
|
||||
internal fun setNewModuleInstances(addedInstances: List<LegacyBridgeModule>) {
|
||||
if (newModuleInstances.isNotEmpty()) error("newModuleInstances are not empty")
|
||||
for (instance in addedInstances) {
|
||||
newModuleInstances[instance.moduleEntityId] = instance
|
||||
val unloadedNames = UnloadedModulesListStorage.getInstance(project).unloadedModuleNames.toSet()
|
||||
val entities = manager.entityStore.current.entities(ModuleEntity::class.java)
|
||||
.filter { !unloadedNames.contains(it.name) }
|
||||
.toList()
|
||||
manager.loadModules(entities)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getModuleRootComponentByLibrary(entity: LibraryEntity): LegacyBridgeModuleRootComponent {
|
||||
val tableId = entity.tableId as LibraryTableId.ModuleLibraryTableId
|
||||
val module = modulesMap[tableId.moduleId] ?: error("Could not find module for module library: ${entity.persistentId()}")
|
||||
return LegacyBridgeModuleRootComponent.getInstance(module)
|
||||
}
|
||||
|
||||
init {
|
||||
// default project doesn't have modules
|
||||
if (!project.isDefault) {
|
||||
val myMessageBusConnection = project.messageBus.connect(this)
|
||||
myMessageBusConnection.subscribe(ProjectLifecycleListener.TOPIC, object : ProjectLifecycleListener {
|
||||
override fun projectComponentsInitialized(listenedProject: Project) {
|
||||
if (project !== listenedProject) return
|
||||
val busConnection = project.messageBus.connect(this)
|
||||
busConnection.subscribe(ProjectManager.TOPIC, object : ProjectManagerListener {
|
||||
override fun projectOpened(eventProject: Project) {
|
||||
if (project == eventProject) {
|
||||
fireModulesAdded()
|
||||
for (module in idToModule.values) {
|
||||
(module as ModuleEx).projectOpened()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val unloadedNames = UnloadedModulesListStorage.getInstance(project).unloadedModuleNames.toSet()
|
||||
|
||||
val entities = entityStore.current.entities(ModuleEntity::class.java)
|
||||
.filter { !unloadedNames.contains(it.name) }
|
||||
.toList()
|
||||
loadModules(entities)
|
||||
override fun projectClosed(eventProject: Project) {
|
||||
if (project == eventProject) {
|
||||
for (module in idToModule.values) {
|
||||
(module as ModuleEx).projectClosed()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
myMessageBusConnection.subscribe(WorkspaceModelTopics.CHANGED, object : WorkspaceModelChangeListener {
|
||||
busConnection.subscribe(WorkspaceModelTopics.CHANGED, object : WorkspaceModelChangeListener {
|
||||
override fun changed(event: EntityStoreChanged) = LOG.bracket("ModuleManagerComponent.EntityStoreChange") {
|
||||
val moduleLibraryChanges = event.getChanges(LibraryEntity::class.java).filterModuleLibraryChanges()
|
||||
val changes = event.getChanges(ModuleEntity::class.java)
|
||||
@@ -152,7 +157,8 @@ class LegacyBridgeModuleManagerComponent(private val project: Project) : ModuleM
|
||||
alreadyCreatedModule.diff = null
|
||||
addModule(alreadyCreatedModule)
|
||||
alreadyCreatedModule
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
if (change.entity.name in unloadedModules.keys) {
|
||||
// Skip unloaded modules if it was not added via API
|
||||
continue@nextChange
|
||||
@@ -174,7 +180,7 @@ class LegacyBridgeModuleManagerComponent(private val project: Project) : ModuleM
|
||||
unloadedModulesSet.remove(change.newEntity.name)
|
||||
unloadedModules.remove(change.newEntity.name)
|
||||
renameModule(oldId, newId)
|
||||
oldModuleNames[modulesMap.getValue(newId)] = oldId.name
|
||||
oldModuleNames[idToModule.getValue(newId)] = oldId.name
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -237,12 +243,26 @@ class LegacyBridgeModuleManagerComponent(private val project: Project) : ModuleM
|
||||
}
|
||||
}
|
||||
})
|
||||
myMessageBusConnection.subscribe(WorkspaceModelTopics.CHANGED, FacetEntityChangeListener(project))
|
||||
busConnection.subscribe(WorkspaceModelTopics.CHANGED, FacetEntityChangeListener(project))
|
||||
}
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
internal fun setNewModuleInstances(addedInstances: List<LegacyBridgeModule>) {
|
||||
if (newModuleInstances.isNotEmpty()) error("newModuleInstances are not empty")
|
||||
for (instance in addedInstances) {
|
||||
newModuleInstances[instance.moduleEntityId] = instance
|
||||
}
|
||||
}
|
||||
|
||||
private fun getModuleRootComponentByLibrary(entity: LibraryEntity): LegacyBridgeModuleRootComponent {
|
||||
val tableId = entity.tableId as LibraryTableId.ModuleLibraryTableId
|
||||
val module = idToModule[tableId.moduleId] ?: error("Could not find module for module library: ${entity.persistentId()}")
|
||||
return LegacyBridgeModuleRootComponent.getInstance(module)
|
||||
}
|
||||
|
||||
internal fun addModule(moduleEntity: ModuleEntity): LegacyBridgeModule {
|
||||
if (modulesMap.containsKey(moduleEntity.persistentId())) {
|
||||
if (idToModule.containsKey(moduleEntity.persistentId())) {
|
||||
error("Module ${moduleEntity.name} (id:'${moduleEntity.persistentId()}') is already added")
|
||||
}
|
||||
|
||||
@@ -252,27 +272,27 @@ class LegacyBridgeModuleManagerComponent(private val project: Project) : ModuleM
|
||||
}
|
||||
|
||||
internal fun addModule(module: LegacyBridgeModule) {
|
||||
val oldValue = modulesMap.put(module.moduleEntityId, module)
|
||||
val oldValue = idToModule.put(module.moduleEntityId, module)
|
||||
if (oldValue != null) {
|
||||
LOG.warn("Duplicate module name: ${module.name}")
|
||||
}
|
||||
}
|
||||
|
||||
internal fun removeModuleAndFireEvent(moduleEntityId: ModuleId) {
|
||||
val moduleImpl = modulesMap.remove(moduleEntityId) ?: error("Module $moduleEntityId does not exist")
|
||||
val moduleImpl = idToModule.remove(moduleEntityId) ?: error("Module $moduleEntityId does not exist")
|
||||
project.messageBus.syncPublisher(ProjectTopics.MODULES).moduleRemoved(project, moduleImpl)
|
||||
Disposer.dispose(moduleImpl)
|
||||
}
|
||||
|
||||
internal fun fireBeforeModuleRemoved(moduleEntityId: ModuleId) {
|
||||
val moduleImpl = modulesMap[moduleEntityId] ?: error("Module $moduleEntityId does not exist")
|
||||
val moduleImpl = idToModule[moduleEntityId] ?: error("Module $moduleEntityId does not exist")
|
||||
project.messageBus.syncPublisher(ProjectTopics.MODULES).beforeModuleRemoved(project, moduleImpl)
|
||||
}
|
||||
|
||||
internal fun renameModule(oldId: ModuleId, newId: ModuleId) {
|
||||
val moduleImpl = modulesMap.remove(oldId) ?: error("Module $oldId does not exist")
|
||||
val moduleImpl = idToModule.remove(oldId) ?: error("Module $oldId does not exist")
|
||||
|
||||
val replacedModuleImplById = modulesMap.put(newId, moduleImpl)
|
||||
val replacedModuleImplById = idToModule.put(newId, moduleImpl)
|
||||
if (replacedModuleImplById != null) {
|
||||
error("ModuleId $newId already exists")
|
||||
}
|
||||
@@ -289,7 +309,7 @@ class LegacyBridgeModuleManagerComponent(private val project: Project) : ModuleM
|
||||
override fun moduleGraph(): Graph<Module> = moduleGraph(includeTests = true)
|
||||
override fun moduleGraph(includeTests: Boolean): Graph<Module> {
|
||||
return GraphGenerator.generate(CachingSemiGraph.cache(object : InboundSemiGraph<Module> {
|
||||
override fun getNodes(): Collection<Module> = this@LegacyBridgeModuleManagerComponent.modulesMap.values.toMutableList()
|
||||
override fun getNodes(): Collection<Module> = this@LegacyBridgeModuleManagerComponent.idToModule.values.toMutableList()
|
||||
|
||||
override fun getIn(m: Module): Iterator<Module> {
|
||||
val dependentModules = ModuleRootManager.getInstance(m).getDependencies(includeTests)
|
||||
@@ -319,22 +339,8 @@ class LegacyBridgeModuleManagerComponent(private val project: Project) : ModuleM
|
||||
}
|
||||
}
|
||||
|
||||
override fun projectOpened() {
|
||||
fireModulesAdded()
|
||||
|
||||
for (module in modulesMap.values) {
|
||||
(module as ModuleEx).projectOpened()
|
||||
}
|
||||
}
|
||||
|
||||
override fun projectClosed() {
|
||||
for (module in modulesMap.values) {
|
||||
(module as ModuleEx).projectClosed()
|
||||
}
|
||||
}
|
||||
|
||||
private fun fireModulesAdded() {
|
||||
for (module in modulesMap.values) {
|
||||
for (module in idToModule.values) {
|
||||
fireModuleAddedInWriteAction(module as ModuleEx)
|
||||
}
|
||||
}
|
||||
@@ -386,7 +392,7 @@ class LegacyBridgeModuleManagerComponent(private val project: Project) : ModuleM
|
||||
ModuleRootManager.getInstance(module).isDependsOn(onModule)
|
||||
|
||||
override fun getAllModuleDescriptions(): MutableCollection<ModuleDescription> =
|
||||
(modulesMap.values.map { module ->
|
||||
(idToModule.values.map { module ->
|
||||
object : ModuleDescription {
|
||||
override fun getName(): String = module.name
|
||||
|
||||
@@ -427,17 +433,17 @@ class LegacyBridgeModuleManagerComponent(private val project: Project) : ModuleM
|
||||
return getUnloadedModuleDescription(moduleEntity)
|
||||
}
|
||||
|
||||
override fun getModules(): Array<Module> = modulesMap.values.toTypedArray()
|
||||
override fun getModules(): Array<Module> = idToModule.values.toTypedArray()
|
||||
|
||||
private val sortedModulesValue = CachedValueWithParameter<Set<ModuleId>, Array<Module>> { _, _ ->
|
||||
val allModules = modulesMap.values.toTypedArray<Module>()
|
||||
val allModules = idToModule.values.toTypedArray<Module>()
|
||||
Arrays.sort(allModules, moduleDependencyComparator())
|
||||
return@CachedValueWithParameter allModules
|
||||
}
|
||||
|
||||
override fun getSortedModules(): Array<Module> = entityStore.cachedValue(sortedModulesValue, modulesMap.keys.toSet())
|
||||
override fun getSortedModules(): Array<Module> = entityStore.cachedValue(sortedModulesValue, idToModule.keys.toSet())
|
||||
|
||||
override fun findModuleByName(name: String): Module? = modulesMap[ModuleId(name)]
|
||||
override fun findModuleByName(name: String): Module? = idToModule[ModuleId(name)]
|
||||
|
||||
override fun disposeModule(module: Module) = ApplicationManager.getApplication().runWriteAction {
|
||||
val modifiableModel = modifiableModel
|
||||
@@ -567,8 +573,9 @@ class LegacyBridgeModuleManagerComponent(private val project: Project) : ModuleM
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun getInstance(project: Project): LegacyBridgeModuleManagerComponent =
|
||||
ModuleManagerComponent.getInstance(project) as LegacyBridgeModuleManagerComponent
|
||||
fun getInstance(project: Project): LegacyBridgeModuleManagerComponent {
|
||||
return ModuleManagerComponent.getInstance(project) as LegacyBridgeModuleManagerComponent
|
||||
}
|
||||
|
||||
private fun List<EntityChange<LibraryEntity>>.filterModuleLibraryChanges() =
|
||||
filter {
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
// 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.
|
||||
// Copyright 2000-2020 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.workspace.legacyBridge.intellij
|
||||
|
||||
import com.intellij.ide.plugins.PluginManagerCore
|
||||
@@ -30,7 +30,7 @@ class LegacyBridgeProjectLifecycleListener : ProjectServiceContainerCustomizer {
|
||||
fun enabled(project: Project) = ModuleManager.getInstance(project) is LegacyBridgeModuleManagerComponent
|
||||
}
|
||||
|
||||
override fun serviceContainerInitialized(project: Project) {
|
||||
override fun serviceRegistered(project: Project) {
|
||||
val enabled = Registry.`is`(ENABLED_REGISTRY_KEY) || WorkspaceModelInitialTestContent.peek() != null
|
||||
if (!enabled) {
|
||||
LOG.info("Using legacy project model to open project")
|
||||
|
||||
Reference in New Issue
Block a user