don't schedule "checkUnknownMacros" for each module using project post start up activity — in any case we check it for project post start up

This commit is contained in:
Vladimir Krivosheev
2015-09-05 13:28:26 +02:00
parent d8460bc7b0
commit e6bbfa9db1
9 changed files with 106 additions and 111 deletions
@@ -54,8 +54,6 @@ open class ProjectStoreImpl(override val project: ProjectImpl, private val pathM
assert(!project.isDefault())
}
override fun getSubstitutors() = listOf(storageManager.getMacroSubstitutor())
override fun optimizeTestLoading() = project.isOptimiseTestLoadSpeed()
override final fun getPathMacroManagerForDefaults() = pathMacroManager
@@ -17,7 +17,6 @@ package com.intellij.configurationStore
import com.intellij.openapi.components.PathMacroManager
import com.intellij.openapi.components.StateStorage.SaveSession
import com.intellij.openapi.components.TrackingPathMacroSubstitutor
import com.intellij.openapi.components.impl.stores.IComponentStore
import com.intellij.openapi.components.stateStore
import com.intellij.openapi.module.Module
@@ -26,8 +25,6 @@ import com.intellij.openapi.project.impl.ProjectImpl
import com.intellij.openapi.project.impl.ProjectStoreClassProvider
import com.intellij.openapi.util.Pair
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.util.SmartList
import com.intellij.util.containers.ContainerUtil
class PlatformLangProjectStoreClassProvider : ProjectStoreClassProvider {
override fun getProjectStoreClass(isDefaultProject: Boolean): Class<out IComponentStore> {
@@ -36,22 +33,10 @@ class PlatformLangProjectStoreClassProvider : ProjectStoreClassProvider {
}
class ProjectWithModulesStoreImpl(project: ProjectImpl, pathMacroManager: PathMacroManager) : ProjectStoreImpl(project, pathMacroManager) {
override fun getSubstitutors(): List<TrackingPathMacroSubstitutor> {
val result = SmartList<TrackingPathMacroSubstitutor>()
ContainerUtil.addIfNotNull(result, storageManager.getMacroSubstitutor())
for (module in getPersistentModules()) {
ContainerUtil.addIfNotNull(result, module.stateStore.getStateStorageManager().getMacroSubstitutor())
}
return result
}
private fun getPersistentModules() = ModuleManager.getInstance(project)?.getModules() ?: Module.EMPTY_ARRAY
override protected fun beforeSave(readonlyFiles: List<Pair<SaveSession, VirtualFile>>) {
override fun beforeSave(readonlyFiles: List<Pair<SaveSession, VirtualFile>>) {
super.beforeSave(readonlyFiles)
for (module in getPersistentModules()) {
for (module in (ModuleManager.getInstance(project)?.getModules() ?: Module.EMPTY_ARRAY)) {
module.stateStore.save(readonlyFiles)
}
}
@@ -25,7 +25,6 @@ import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
import com.intellij.openapi.components.StoragePathMacros;
import com.intellij.openapi.components.StorageScheme;
import com.intellij.openapi.components.impl.stores.StorageUtil;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleType;
@@ -40,7 +39,6 @@ import com.intellij.util.messages.MessageBusConnection;
import com.intellij.util.messages.MessageHandler;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.List;
@@ -119,10 +117,8 @@ public class ModuleManagerComponent extends ModuleManagerImpl {
@NotNull
@Override
protected ModuleEx createAndLoadModule(@NotNull String filePath) throws IOException {
ModuleImpl module = new ModuleImpl(filePath, myProject);
StorageUtil.checkUnknownMacros(module, myProject);
return module;
protected ModuleEx createAndLoadModule(@NotNull String filePath) {
return new ModuleImpl(filePath, myProject);
}
@Override
@@ -16,7 +16,6 @@
package com.intellij.application.options.pathMacros;
import com.intellij.openapi.application.ApplicationBundle;
import com.intellij.openapi.components.ComponentsPackage;
import com.intellij.openapi.components.impl.stores.StorageUtil;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurationException;
@@ -48,7 +47,7 @@ public class PathMacroConfigurable implements SearchableConfigurable, Configurab
myEditor.commit();
for (Project project : ProjectManager.getInstance().getOpenProjects()) {
StorageUtil.checkUnknownMacros(ComponentsPackage.getStateStore(project), project, false);
StorageUtil.checkUnknownMacros(project, false);
}
}
@@ -16,14 +16,11 @@
package com.intellij.openapi.components.impl.stores;
import com.intellij.openapi.components.StorageScheme;
import com.intellij.openapi.components.TrackingPathMacroSubstitutor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public interface IProjectStore extends IComponentStore {
@Nullable
VirtualFile getProjectBaseDir();
@@ -37,9 +34,6 @@ public interface IProjectStore extends IComponentStore {
@NotNull
String getProjectName();
@NotNull
List<TrackingPathMacroSubstitutor> getSubstitutors();
@NotNull
StorageScheme getStorageScheme();
@@ -24,11 +24,12 @@ import com.intellij.openapi.components.ComponentManager;
import com.intellij.openapi.components.ComponentsPackage;
import com.intellij.openapi.components.TrackingPathMacroSubstitutor;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectBundle;
import com.intellij.openapi.project.ex.ProjectManagerEx;
import com.intellij.openapi.project.impl.ProjectMacrosUtil;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
@@ -55,32 +56,18 @@ public class StorageUtil {
private StorageUtil() { }
public static void checkUnknownMacros(@NotNull final ComponentManager componentManager, @NotNull final Project project) {
Application application = ApplicationManager.getApplication();
if (application.isHeadlessEnvironment() || application.isUnitTestMode()) {
return;
}
// should be invoked last
StartupManager.getInstance(project).runWhenProjectIsInitialized(new Runnable() {
@Override
public void run() {
notifyUnknownMacros(ComponentsPackage.getStateStore(componentManager), project, null);
}
});
}
public static void notifyUnknownMacros(@NotNull final IComponentStore store, @NotNull final Project project, @Nullable final String componentName) {
TrackingPathMacroSubstitutor substitutor = store.getStateStorageManager().getMacroSubstitutor();
public static void notifyUnknownMacros(@NotNull final IComponentStore store, @NotNull final Project project, @NotNull final String componentName) {
final TrackingPathMacroSubstitutor substitutor = store.getStateStorageManager().getMacroSubstitutor();
if (substitutor == null) {
return;
}
final LinkedHashSet<String> macros = new LinkedHashSet<String>(substitutor.getUnknownMacros(componentName));
if (macros.isEmpty()) {
Set<String> immutableMacros = substitutor.getUnknownMacros(componentName);
if (immutableMacros.isEmpty()) {
return;
}
final Set<String> macros = new LinkedHashSet<String>(immutableMacros);
AppUIUtil.invokeOnEdt(new Runnable() {
@Override
public void run() {
@@ -101,77 +88,109 @@ public class StorageUtil {
}
LOG.debug("Reporting unknown path macros " + macros + " in component " + componentName);
String format = "<p><i>%s</i> %s undefined. <a href=\"define\">Fix it</a></p>";
String productName = ApplicationNamesInfo.getInstance().getProductName();
String content = String.format(format, StringUtil.join(macros, ", "), macros.size() == 1 ? "is" : "are") +
"<br>Path variables are used to substitute absolute paths " +
"in " + productName + " project files " +
"and allow project file sharing in version control systems.<br>" +
"Some of the files describing the current project settings contain unknown path variables " +
"and " + productName + " cannot restore those paths.";
new UnknownMacroNotification("Load Error", "Load error: undefined path variables", content, NotificationType.ERROR,
new NotificationListener() {
@Override
public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) {
checkUnknownMacros(store, project, true);
}
}, macros).notify(project);
doNotify(macros, project, Collections.singletonMap(substitutor, store));
}
}, project.getDisposed());
}
public static void checkUnknownMacros(@NotNull IComponentStore store, @NotNull Project project, boolean showDialog) {
// default project doesn't have it
List<TrackingPathMacroSubstitutor> substitutors;
if (store instanceof IProjectStore) {
substitutors = ((IProjectStore)store).getSubstitutors();
}
else {
substitutors = Collections.emptyList();
}
Set<String> unknownMacros = new THashSet<String>();
for (TrackingPathMacroSubstitutor substitutor : substitutors) {
unknownMacros.addAll(substitutor.getUnknownMacros(null));
private static void doNotify(@NotNull final Set<String> macros, @NotNull final Project project,
@NotNull final Map<TrackingPathMacroSubstitutor, IComponentStore> substitutorToStore) {
String format = "<p><i>%s</i> %s undefined. <a href=\"define\">Fix it</a></p>";
String productName = ApplicationNamesInfo.getInstance().getProductName();
String content = String.format(format, StringUtil.join(macros, ", "), macros.size() == 1 ? "is" : "are") +
"<br>Path variables are used to substitute absolute paths " +
"in " + productName + " project files " +
"and allow project file sharing in version control systems.<br>" +
"Some of the files describing the current project settings contain unknown path variables " +
"and " + productName + " cannot restore those paths.";
new UnknownMacroNotification("Load Error", "Load error: undefined path variables", content, NotificationType.ERROR,
new NotificationListener() {
@Override
public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) {
checkUnknownMacros(project, true, macros, substitutorToStore);
}
}, macros).notify(project);
}
public static void checkUnknownMacros(@NotNull Project project, boolean notify) {
// use linked set/map to get stable results
Set<String> unknownMacros = new LinkedHashSet<String>();
Map<TrackingPathMacroSubstitutor, IComponentStore> substitutorToStore = ContainerUtil.newLinkedHashMap();
collect(project, unknownMacros, substitutorToStore);
for (Module module : ModuleManager.getInstance(project).getModules()) {
collect(module, unknownMacros, substitutorToStore);
}
if (unknownMacros.isEmpty() || showDialog && !ProjectMacrosUtil.checkMacros(project, new THashSet<String>(unknownMacros))) {
if (unknownMacros.isEmpty()) {
return;
}
final PathMacros pathMacros = PathMacros.getInstance();
final Set<String> macrosToInvalidate = new THashSet<String>(unknownMacros);
for (Iterator<String> it = macrosToInvalidate.iterator(); it.hasNext(); ) {
if (notify) {
doNotify(unknownMacros, project, substitutorToStore);
return;
}
checkUnknownMacros(project, false, unknownMacros, substitutorToStore);
}
private static void checkUnknownMacros(@NotNull Project project,
boolean showDialog,
@NotNull Set<String> unknownMacros,
@NotNull Map<TrackingPathMacroSubstitutor, IComponentStore> substitutorToStore) {
if (unknownMacros.isEmpty() || (showDialog && !ProjectMacrosUtil.checkMacros(project, new THashSet<String>(unknownMacros)))) {
return;
}
PathMacros pathMacros = PathMacros.getInstance();
for (Iterator<String> it = unknownMacros.iterator(); it.hasNext(); ) {
String macro = it.next();
if (StringUtil.isEmptyOrSpaces(pathMacros.getValue(macro)) && !pathMacros.isIgnoredMacroName(macro)) {
it.remove();
}
}
if (macrosToInvalidate.isEmpty()) {
if (unknownMacros.isEmpty()) {
return;
}
Set<String> components = new THashSet<String>();
for (TrackingPathMacroSubstitutor substitutor : substitutors) {
components.addAll(substitutor.getComponents(macrosToInvalidate));
}
for (Map.Entry<TrackingPathMacroSubstitutor, IComponentStore> entry : substitutorToStore.entrySet()) {
TrackingPathMacroSubstitutor substitutor = entry.getKey();
Set<String> components = substitutor.getComponents(unknownMacros);
IComponentStore store = entry.getValue();
if (store.isReloadPossible(components)) {
substitutor.invalidateUnknownMacros(unknownMacros);
if (store.isReloadPossible(components)) {
for (TrackingPathMacroSubstitutor substitutor : substitutors) {
substitutor.invalidateUnknownMacros(macrosToInvalidate);
}
for (UnknownMacroNotification notification : NotificationsManager.getNotificationsManager().getNotificationsOfType(UnknownMacroNotification.class, project)) {
if (macrosToInvalidate.containsAll(notification.getMacros())) {
notification.expire();
for (UnknownMacroNotification notification : NotificationsManager.getNotificationsManager().getNotificationsOfType(UnknownMacroNotification.class, project)) {
if (unknownMacros.containsAll(notification.getMacros())) {
notification.expire();
}
}
}
store.reloadStates(components, project.getMessageBus());
store.reloadStates(components, project.getMessageBus());
}
else if (Messages.showYesNoDialog(project, "Component could not be reloaded. Reload project?", "Configuration Changed",
Messages.getQuestionIcon()) == Messages.YES) {
ProjectManagerEx.getInstanceEx().reloadProject(project);
}
}
else if (Messages.showYesNoDialog(project, "Component could not be reloaded. Reload project?", "Configuration Changed", Messages.getQuestionIcon()) == Messages.YES) {
ProjectManagerEx.getInstanceEx().reloadProject(project);
}
private static void collect(@NotNull ComponentManager componentManager,
@NotNull Set<String> unknownMacros,
@NotNull Map<TrackingPathMacroSubstitutor, IComponentStore> substitutorToStore) {
IComponentStore store = ComponentsPackage.getStateStore(componentManager);
TrackingPathMacroSubstitutor substitutor = store.getStateStorageManager().getMacroSubstitutor();
if (substitutor == null) {
return;
}
Set<String> macros = substitutor.getUnknownMacros(null);
if (macros.isEmpty()) {
return;
}
unknownMacros.addAll(macros);
substitutorToStore.put(substitutor, store);
}
@NotNull
@@ -28,6 +28,7 @@ import com.intellij.notification.NotificationListener;
import com.intellij.notification.NotificationType;
import com.intellij.notification.NotificationsManager;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ApplicationNamesInfo;
import com.intellij.openapi.application.ModalityState;
@@ -387,6 +388,11 @@ public class ProjectManagerImpl extends ProjectManagerEx implements Disposable {
public void run() {
if (!project.isDisposed()) {
startupManager.runPostStartupActivities();
Application application = ApplicationManager.getApplication();
if (!(application.isHeadlessEnvironment() || application.isUnitTestMode())) {
StorageUtil.checkUnknownMacros(project, true);
}
}
}
});
@@ -399,8 +405,6 @@ public class ProjectManagerImpl extends ProjectManagerEx implements Disposable {
return false;
}
StorageUtil.checkUnknownMacros(project, project);
return true;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,10 +23,11 @@ import java.util.Set;
public interface TrackingPathMacroSubstitutor extends PathMacroSubstitutor {
@NotNull
Collection<String> getUnknownMacros(@Nullable String componentName);
Set<String> getUnknownMacros(@Nullable String componentName);
// Mutable set
@NotNull
Collection<String> getComponents(@NotNull Collection<String> macros);
Set<String> getComponents(@NotNull Collection<String> macros);
void addUnknownMacros(@NotNull String componentName, @NotNull Collection<String> unknownMacros);
@@ -35,7 +35,6 @@ import com.intellij.openapi.vfs.VirtualFileSystem;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.MultiMap;
import com.intellij.util.containers.SmartHashSet;
import gnu.trove.THashSet;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -217,7 +216,7 @@ public class BasePathMacroManager extends PathMacroManager {
@NotNull
@Override
public Collection<String> getComponents(@NotNull Collection<String> macros) {
public Set<String> getComponents(@NotNull Collection<String> macros) {
synchronized (myLock) {
Set<String> result = new SmartHashSet<String>();
for (String macro : macros) {
@@ -229,10 +228,10 @@ public class BasePathMacroManager extends PathMacroManager {
@NotNull
@Override
public Collection<String> getUnknownMacros(@Nullable String componentName) {
public Set<String> getUnknownMacros(@Nullable String componentName) {
synchronized (myLock) {
Collection<String> list = componentName == null ? myMacroToComponentNames.keySet() : myComponentNameToMacros.get(componentName);
return ContainerUtil.isEmpty(list) ? Collections.<String>emptyList() : new THashSet<String>(list);
Set<String> list = componentName == null ? myMacroToComponentNames.keySet() : (Set<String>)myComponentNameToMacros.get(componentName);
return ContainerUtil.isEmpty(list) ? Collections.<String>emptySet() : Collections.unmodifiableSet(list);
}
}