Merge remote-tracking branch 'origin/master'

This commit is contained in:
Roman Shevchenko
2015-07-23 17:11:00 +02:00
63 changed files with 2093 additions and 2731 deletions
@@ -476,10 +476,16 @@ public class JVMNameUtil {
@Nullable
public static String getClassVMName(@Nullable PsiClass containingClass) {
if (containingClass == null) return null;
// no support for local classes for now
if (containingClass == null || PsiUtil.isLocalClass(containingClass)) return null;
if (containingClass instanceof PsiAnonymousClass) {
return getClassVMName(PsiTreeUtil.getParentOfType(containingClass, PsiClass.class)) +
JavaAnonymousClassesHelper.getName((PsiAnonymousClass)containingClass);
String parentName = getClassVMName(PsiTreeUtil.getParentOfType(containingClass, PsiClass.class));
if (parentName == null) {
return null;
}
else {
return parentName + JavaAnonymousClassesHelper.getName((PsiAnonymousClass)containingClass);
}
}
return ClassUtil.getJVMClassName(containingClass);
}
@@ -213,8 +213,8 @@ public class PositionManagerImpl implements PositionManager, MultiRequestPositio
}
private PsiElement remapElement(PsiElement element) {
PsiClass aClass = getEnclosingClass(element);
if (!Comparing.equal(myExpectedClassName, JVMNameUtil.getClassVMName(aClass))) {
String name = JVMNameUtil.getClassVMName(getEnclosingClass(element));
if (name != null && !name.equals(myExpectedClassName)) {
return null;
}
PsiElement method = DebuggerUtilsEx.getContainingMethod(element);
@@ -25,6 +25,7 @@ import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.fileChooser.FileChooserFactory;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectBundle;
import com.intellij.openapi.project.ex.ProjectEx;
@@ -224,35 +225,39 @@ public class ProjectConfigurable extends ProjectStructureElementConfigurable<Pro
throw new ConfigurationException("Please, specify project name!");
}
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
DumbService.getInstance(myProject).allowStartingDumbModeInside(DumbService.DumbModePermission.MAY_START_BACKGROUND, new Runnable() {
public void run() {
// set the output path first so that handlers of RootsChanged event sent after JDK is set
// would see the updated path
String canonicalPath = myProjectCompilerOutput.getText();
if (canonicalPath != null && canonicalPath.length() > 0) {
try {
canonicalPath = FileUtil.resolveShortWindowsName(canonicalPath);
}
catch (IOException e) {
//file doesn't exist yet
}
canonicalPath = FileUtil.toSystemIndependentName(canonicalPath);
compilerProjectExtension.setCompilerOutputUrl(VfsUtilCore.pathToUrl(canonicalPath));
}
else {
compilerProjectExtension.setCompilerOutputPointer(null);
}
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
// set the output path first so that handlers of RootsChanged event sent after JDK is set
// would see the updated path
String canonicalPath = myProjectCompilerOutput.getText();
if (canonicalPath != null && canonicalPath.length() > 0) {
try {
canonicalPath = FileUtil.resolveShortWindowsName(canonicalPath);
}
catch (IOException e) {
//file doesn't exist yet
}
canonicalPath = FileUtil.toSystemIndependentName(canonicalPath);
compilerProjectExtension.setCompilerOutputUrl(VfsUtilCore.pathToUrl(canonicalPath));
}
else {
compilerProjectExtension.setCompilerOutputPointer(null);
}
LanguageLevelProjectExtension extension = LanguageLevelProjectExtension.getInstance(myProject);
extension.setLanguageLevel(myLanguageLevelCombo.getSelectedLevel());
extension.setDefault(myLanguageLevelCombo.isDefault());
myProjectJdkConfigurable.apply();
LanguageLevelProjectExtension extension = LanguageLevelProjectExtension.getInstance(myProject);
extension.setLanguageLevel(myLanguageLevelCombo.getSelectedLevel());
extension.setDefault(myLanguageLevelCombo.isDefault());
myProjectJdkConfigurable.apply();
if (myProjectName != null) {
((ProjectEx)myProject).setProjectName(myProjectName.getText().trim());
if (myDetailsComponent != null) myDetailsComponent.setText(getBannerSlogan());
}
if (myProjectName != null) {
((ProjectEx)myProject).setProjectName(myProjectName.getText().trim());
if (myDetailsComponent != null) myDetailsComponent.setText(getBannerSlogan());
}
}
});
}
});
}
@@ -144,7 +144,7 @@ public abstract class ExecutionWithDebuggerToolsTestCase extends ExecutionTestCa
}
catch (AssertionError e) {
addException(e);
paused(suspendContext);
resume(suspendContext);
}
if (myScriptRunnables.isEmpty()) {
@@ -143,25 +143,28 @@ public class Main {
return args.length > 0 && Comparing.strEqual(args[0], "traverseUI");
}
private static boolean checkBundledJava(File java) throws IOException {
private static boolean checkBundledJava(File java) throws Exception {
String[] command = new String[]{java.getPath(), "-version"};
try {
Process process = Runtime.getRuntime().exec(command);
String line = (new BufferedReader(new InputStreamReader(process.getErrorStream()))).readLine();
if (line != null && (line.toLowerCase().startsWith("java version") || (line.toLowerCase().startsWith("openjdk version")))){
String[] javaVersion = line.split("\\.");
int i = 1;
if (javaVersion.length > i && Integer.parseInt(javaVersion[i]) > 5) {
return true;
int pos = line.indexOf('.');
if (pos > 0){
int majorVersion = Integer.parseInt(line.substring(pos-1, pos));
int minorVersion = Integer.parseInt(line.substring(pos+1, pos+2));
if (majorVersion > 1 || minorVersion > 5) {
return true;
}
}
}
} catch (IOException e) {
} catch (Exception e) {
System.out.println("updater: the java: " + command[0] + " is invalid.");
}
return false;
}
private static String getBundledJava(String javaHome) throws IOException {
private static String getBundledJava(String javaHome) throws Exception {
String javaHomeCopy = System.getProperty("user.home") + "/." + System.getProperty("idea.paths.selector") + "/restart/jre";
File javaCopy = SystemInfoRt.isWindows ? new File(javaHomeCopy + "/bin/java.exe") : new File(javaHomeCopy + "/bin/java");
if (javaCopy != null && javaCopy.isFile() && checkBundledJava(javaCopy)) {
@@ -177,7 +180,7 @@ public class Main {
return javaHome;
}
private static String getJava() throws IOException {
private static String getJava() throws Exception {
String javaHome = System.getProperty("java.home");
if (javaHome.toLowerCase().startsWith(PathManager.getHomePath().toLowerCase())) {
System.out.println("Updater: uses bundled java.");
@@ -186,7 +189,7 @@ public class Main {
return javaHome + "/bin/java";
}
private static void installPatch() throws IOException {
private static void installPatch() throws Exception {
String platform = System.getProperty(PLATFORM_PREFIX_PROPERTY, "idea");
String patchFileName = ("jetbrains.patch.jar." + platform).toLowerCase(Locale.US);
String tempDir = System.getProperty("java.io.tmpdir");
@@ -0,0 +1,90 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.configurationStore
import com.intellij.application.options.PathMacrosImpl
import com.intellij.openapi.application.PathManager
import com.intellij.openapi.application.impl.ApplicationImpl
import com.intellij.openapi.components.PathMacroManager
import com.intellij.openapi.components.StateStorage
import com.intellij.openapi.components.StateStorageOperation
import com.intellij.openapi.components.StoragePathMacros
import com.intellij.openapi.components.impl.BasePathMacroManager
import com.intellij.openapi.components.impl.stores.DirectoryStorageData
import com.intellij.openapi.components.impl.stores.StateStorageManager
import com.intellij.openapi.components.impl.stores.StorageData
import com.intellij.openapi.util.NamedJDOMExternalizable
import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.openapi.vfs.VfsUtil
class ApplicationPathMacroManager : BasePathMacroManager(null)
class ApplicationStoreImpl(private val application: ApplicationImpl, pathMacroManager: PathMacroManager) : ComponentStoreImpl() {
private val stateStorageManager: StateStorageManager
companion object {
private val DEFAULT_STORAGE_SPEC = "${StoragePathMacros.APP_CONFIG}/${PathManager.DEFAULT_OPTIONS_FILE_NAME}${DirectoryStorageData.DEFAULT_EXT}"
}
init {
stateStorageManager = object : StateStorageManagerImpl(pathMacroManager.createTrackingSubstitutor(), "application", application, application.getPicoContainer()) {
private var configDirectoryRefreshed = false
override fun createStorageTopicListener() = application.getMessageBus().syncPublisher(StateStorage.STORAGE_TOPIC)
override fun createStorageData(fileSpec: String, filePath: String) = StorageData(rootTagName)
override fun getOldStorageSpec(component: Any, componentName: String, operation: StateStorageOperation): String? {
if (component is NamedJDOMExternalizable) {
return "${StoragePathMacros.APP_CONFIG}/${component.getExternalFileName()}${DirectoryStorageData.DEFAULT_EXT}"
}
else {
return DEFAULT_STORAGE_SPEC
}
}
override fun getMacroSubstitutor(fileSpec: String) = if (fileSpec == "${StoragePathMacros.APP_CONFIG}/${PathMacrosImpl.EXT_FILE_NAME}${DirectoryStorageData.DEFAULT_EXT}") null else super.getMacroSubstitutor(fileSpec)
override fun isUseXmlProlog() = false
override fun beforeFileBasedStorageCreate() {
if (configDirectoryRefreshed || (!application.isUnitTestMode() && !application.isDispatchThread())) {
return
}
try {
val configPath = expandMacros(StoragePathMacros.ROOT_CONFIG)
if (configPath == StoragePathMacros.ROOT_CONFIG) {
LOG.warn("Macros ROOT_CONFIG is not defined")
return
}
val configDir = LocalFileSystem.getInstance().refreshAndFindFileByPath(configPath)
if (configDir != null) {
VfsUtil.markDirtyAndRefresh(false, true, true, configDir)
}
}
finally {
configDirectoryRefreshed = true
}
}
}
}
override fun getMessageBus() = application.getMessageBus()
override fun getStateStorageManager() = stateStorageManager
}
@@ -0,0 +1,76 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.configurationStore
import com.intellij.openapi.components.PathMacroManager
import com.intellij.openapi.components.PathMacroSubstitutor
import com.intellij.openapi.components.impl.stores.StateStorageManager
import com.intellij.openapi.components.impl.stores.StorageData
import org.jdom.Element
import kotlin.properties.Delegates
abstract class BaseFileConfigurableStoreImpl(protected val pathMacroManager: PathMacroManager) : ComponentStoreImpl() {
val storageManager by Delegates.lazy { createStorageManager() }
override fun getStateStorageManager() = storageManager
override fun getPathMacroManagerForDefaults() = pathMacroManager
protected abstract fun createStorageManager(): StateStorageManager
}
open class ProjectStorageData : StorageData {
companion object {
val CURRENT_FORMAT_VERSION = 4
val VERSION_OPTION: String = "version"
}
private var version = CURRENT_FORMAT_VERSION
constructor(rootElementName: String) : super(rootElementName) {
}
protected constructor(storageData: ProjectStorageData) : super(storageData) {
}
override fun load(rootElement: Element, pathMacroSubstitutor: PathMacroSubstitutor?, intern: Boolean) {
super.load(rootElement, pathMacroSubstitutor, intern)
version = rootElement.getAttributeValue(VERSION_OPTION)?.toInt() ?: CURRENT_FORMAT_VERSION
}
override fun save(newLiveStates: Map<String, Element>): Element {
var root = super.save(newLiveStates)
if (root == null) {
root = Element(myRootElementName)
}
writeOptions(root, Integer.toString(version))
return root
}
override fun clone() = ProjectStorageData(this)
protected open fun writeOptions(root: Element, versionString: String) {
root.setAttribute(VERSION_OPTION, "4")
}
override fun getChangedComponentNames(newStorageData: StorageData, substitutor: PathMacroSubstitutor?): Set<String>? {
if (version != (newStorageData as ProjectStorageData).version) {
return null
}
return super.getChangedComponentNames(newStorageData, substitutor)
}
}
@@ -0,0 +1,494 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.configurationStore
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.PathManager
import com.intellij.openapi.application.ReadAction
import com.intellij.openapi.application.WriteAction
import com.intellij.openapi.application.ex.DecodeDefaultsUtil
import com.intellij.openapi.components.*
import com.intellij.openapi.components.StateStorage.SaveSession
import com.intellij.openapi.components.StateStorageChooserEx.Resolution
import com.intellij.openapi.components.impl.ComponentManagerImpl
import com.intellij.openapi.components.impl.stores.*
import com.intellij.openapi.components.impl.stores.StateStorageManager.ExternalizationSession
import com.intellij.openapi.components.store.ReadOnlyModificationException
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.progress.ProcessCanceledException
import com.intellij.openapi.project.Project
import com.intellij.openapi.util
import com.intellij.openapi.util.*
import com.intellij.openapi.util.Pair
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess
import com.intellij.util.ArrayUtilRt
import com.intellij.util.ReflectionUtil
import com.intellij.util.SmartList
import com.intellij.util.containers.MultiMap
import com.intellij.util.containers.SmartHashSet
import com.intellij.util.lang.CompoundRuntimeException
import com.intellij.util.messages.MessageBus
import com.intellij.util.xmlb.JDOMXIncluder
import gnu.trove.THashMap
import org.jdom.Element
import org.jdom.JDOMException
import org.jetbrains.annotations.TestOnly
import java.io.File
import java.io.IOException
import java.util.Arrays
import java.util.Collections
import java.util.Comparator
import java.util.LinkedHashSet
import java.util.concurrent.CopyOnWriteArrayList
import kotlin.reflect.jvm.java
private val LOG = Logger.getInstance(javaClass<ComponentStoreImpl>())
public abstract class ComponentStoreImpl : IComponentStore {
private val myComponents = Collections.synchronizedMap(THashMap<String, Any>())
private val mySettingsSavingComponents = CopyOnWriteArrayList<SettingsSavingComponent>()
protected open val defaultStorageChooser: StateStorageChooser<PersistentStateComponent<*>>? = null
override fun initComponent(component: Any, service: Boolean) {
if (component is SettingsSavingComponent) {
mySettingsSavingComponents.add(component)
}
if (!(component is JDOMExternalizable || component is PersistentStateComponent<*>)) {
return
}
val token = ReadAction.start()
try {
val componentNameIfStateExists: String?
if (component is PersistentStateComponent<*>) {
componentNameIfStateExists = initPersistentComponent(component, null, false)
}
else {
componentNameIfStateExists = initJdomExternalizable(component as JDOMExternalizable)
}
// if not service, so, component manager will check it later for all components
if (componentNameIfStateExists != null && service) {
val project = getProject()
val app = ApplicationManager.getApplication()
if (project != null && !app.isHeadlessEnvironment() && !app.isUnitTestMode() && project.isInitialized()) {
val substitutor = getStateStorageManager().getMacroSubstitutor()
if (substitutor != null) {
StorageUtil.notifyUnknownMacros(substitutor, project, componentNameIfStateExists)
}
}
}
}
catch (e: StateStorageException) {
throw e
}
catch (e: ProcessCanceledException) {
throw e
}
catch (e: Exception) {
LOG.error(e)
}
finally {
token.finish()
}
}
override fun save(readonlyFiles: MutableList<util.Pair<StateStorage.SaveSession, VirtualFile>>) {
val externalizationSession = if (myComponents.isEmpty()) null else getStateStorageManager().startExternalization()
if (externalizationSession != null) {
val names = ArrayUtilRt.toStringArray(myComponents.keySet())
Arrays.sort(names)
for (name in names) {
commitComponent(externalizationSession, myComponents.get(name)!!, name)
}
}
var errors: MutableList<Throwable>? = null
for (settingsSavingComponent in mySettingsSavingComponents) {
try {
settingsSavingComponent.save()
}
catch (e: Throwable) {
if (errors == null) {
errors = SmartList<Throwable>()
}
errors.add(e)
}
}
errors = doSave(externalizationSession?.createSaveSessions(), readonlyFiles, errors)
CompoundRuntimeException.doThrow(errors)
}
override TestOnly fun saveApplicationComponent(component: Any) {
val externalizationSession = getStateStorageManager().startExternalization() ?: return
commitComponent(externalizationSession, component, null)
val sessions = externalizationSession.createSaveSessions()
if (sessions.isEmpty()) {
return
}
val file: File
val state = StoreUtil.getStateSpec(component.javaClass)
if (state != null) {
file = File(getStateStorageManager().expandMacros(findNonDeprecated(state.storages).file))
}
else if (component is ExportableApplicationComponent && component is NamedJDOMExternalizable) {
file = PathManager.getOptionsFile(component)
}
else {
throw AssertionError("${component.javaClass} doesn't have @State annotation and doesn't implement ExportableApplicationComponent")
}
val token = WriteAction.start()
try {
VfsRootAccess.allowRootAccess(file.getAbsolutePath())
CompoundRuntimeException.doThrow(doSave(sessions, arrayListOf(), null))
}
finally {
try {
VfsRootAccess.disallowRootAccess(file.getAbsolutePath())
}
finally {
token.finish()
}
}
}
private fun commitComponent(externalizationSession: ExternalizationSession, component: Any, componentName: String?) {
if (component is PersistentStateComponent<*>) {
commitPersistentComponent(component, externalizationSession, componentName)
}
else if (component is JDOMExternalizable) {
externalizationSession.setStateInOldStorage(component, componentName ?: ComponentManagerImpl.getComponentName(component), component)
}
}
protected open fun doSave(saveSessions: List<SaveSession>?, readonlyFiles: MutableList<Pair<SaveSession, VirtualFile>>, prevErrors: MutableList<Throwable>?): MutableList<Throwable>? {
var errors = prevErrors
if (saveSessions != null) {
for (session in saveSessions) {
errors = executeSave(session, readonlyFiles, prevErrors)
}
}
return errors
}
private fun <T> commitPersistentComponent(component: PersistentStateComponent<T>, session: ExternalizationSession, componentName: String?) {
val state = component.getState()
if (state != null) {
val storageSpecs = getComponentStorageSpecs(component, StoreUtil.getStateSpec(component), StateStorageOperation.WRITE)
session.setState(storageSpecs, component, componentName ?: StoreUtil.getComponentName(component), state)
}
}
private fun initJdomExternalizable(component: JDOMExternalizable): String? {
val componentName = ComponentManagerImpl.getComponentName(component)
doAddComponent(componentName, component)
if (optimizeTestLoading()) {
return null
}
loadJdomDefaults(component, componentName)
val stateStorage = getStateStorageManager().getOldStorage(component, componentName, StateStorageOperation.READ) ?: return null
val element = stateStorage.getState<Element>(component, componentName, javaClass<Element>(), null) ?: return null
try {
if (LOG.isDebugEnabled()) {
LOG.debug("Loading configuration for " + component.javaClass)
}
component.readExternal(element)
}
catch (e: InvalidDataException) {
LOG.error(e)
return null
}
return componentName
}
private fun doAddComponent(componentName: String, component: Any) {
val existing = myComponents.get(componentName)
if (existing != null && existing !== component) {
LOG.error("Conflicting component name '" + componentName + "': " + existing.javaClass + " and " + component.javaClass)
}
myComponents.put(componentName, component)
}
private fun loadJdomDefaults(component: JDOMExternalizable, componentName: String) {
try {
val defaultState = getDefaultState(component, componentName, javaClass<Element>())
if (defaultState != null) {
component.readExternal(defaultState)
}
}
catch (e: Exception) {
LOG.error("Cannot load defaults for " + component.javaClass, e)
}
}
protected open fun getProject(): Project? = null
private fun <T> initPersistentComponent(component: PersistentStateComponent<T>, changedStorages: Set<StateStorage>?, reloadData: Boolean): String? {
val stateSpec = StoreUtil.getStateSpec(component)
val name = stateSpec.name
if (changedStorages == null || !reloadData) {
doAddComponent(name, component)
}
if (optimizeTestLoading()) {
return null
}
val stateClass = ComponentSerializationUtil.getStateClass<T>(component.javaClass)
if (!stateSpec.defaultStateAsResource && LOG.isDebugEnabled() && getDefaultState(component, name, stateClass) != null) {
LOG.error(name + " has default state, but not marked to load it")
}
var state = if (stateSpec.defaultStateAsResource) getDefaultState(component, name, stateClass) else null
val storageSpecs = getComponentStorageSpecs(component, stateSpec, StateStorageOperation.READ)
val stateStorageChooser = component as? StateStorageChooserEx
for (storageSpec in storageSpecs) {
val resolution = if (stateStorageChooser == null) Resolution.DO else stateStorageChooser.getResolution(storageSpec, StateStorageOperation.READ)
if (resolution === Resolution.SKIP) {
continue
}
val stateStorage = getStateStorageManager().getStateStorage(storageSpec)
if (stateStorage != null) {
var forcedState = false
if (!stateStorage.hasState(component, name, stateClass, reloadData)) {
forcedState = changedStorages != null && changedStorages.contains(stateStorage)
if (!forcedState) {
continue
}
}
state = stateStorage.getState(component, name, stateClass, state)
if (state == null && forcedState) {
// state will be null if file deleted
// we must create empty (initial) state to reinit component
state = DefaultStateSerializer.deserializeState(Element("state"), stateClass, null)
}
break
}
}
if (state != null) {
component.loadState(state)
}
return name
}
protected open fun getPathMacroManagerForDefaults(): PathMacroManager? = null
protected fun <T : Any> getDefaultState(component: Any, componentName: String, stateClass: Class<T>): T? {
val url = DecodeDefaultsUtil.getDefaults(component, componentName) ?: return null
try {
val documentElement = JDOMXIncluder.resolve(JDOMUtil.loadDocument(url), url.toExternalForm()).detachRootElement()
getPathMacroManagerForDefaults()?.expandPaths(documentElement)
return DefaultStateSerializer.deserializeState<T>(documentElement, stateClass, null)
}
catch (e: IOException) {
throw StateStorageException("Error loading state from " + url, e)
}
catch (e: JDOMException) {
throw StateStorageException("Error loading state from " + url, e)
}
}
protected open fun <T> getComponentStorageSpecs(component: PersistentStateComponent<T>, stateSpec: State, operation: StateStorageOperation): Array<Storage> {
val storages = stateSpec.storages
if (storages.size() == 1 || component is StateStorageChooserEx) {
return storages
}
assert(!storages.isEmpty())
var storageChooserClass = stateSpec.storageChooser.java
if (storageChooserClass != javaClass<StateStorageChooser<*>>()) {
@suppress("UNCHECKED_CAST")
val stateStorageChooser: StateStorageChooser<Any> = ReflectionUtil.newInstance(stateSpec.storageChooser.java as Class<out StateStorageChooser<Any>>)
return stateStorageChooser.selectStorages(storages, component, operation)
}
val defaultChooser = defaultStorageChooser
if (defaultChooser != null) {
return defaultChooser.selectStorages(storages, component, operation)
}
var actualStorageCount = 0
for (storage in storages) {
if (!storage.deprecated) {
actualStorageCount++
}
}
if (actualStorageCount > 1) {
LOG.error("State chooser not specified for: " + component.javaClass)
}
if (!storages[0].deprecated) {
var othersAreDeprecated = true
for (i in 1..storages.size() - 1) {
if (!storages[i].deprecated) {
othersAreDeprecated = false
break
}
}
if (othersAreDeprecated) {
return storages
}
}
val sorted = Arrays.copyOf(storages, storages.size())
Arrays.sort(sorted, object : Comparator<Storage> {
override fun compare(o1: Storage, o2: Storage): Int {
val w1 = if (o1.deprecated) 1 else 0
val w2 = if (o2.deprecated) 1 else 0
return w1 - w2
}
})
return sorted
}
protected open fun optimizeTestLoading(): Boolean = false
override fun isReloadPossible(componentNames: Set<String>): Boolean {
for (componentName in componentNames) {
val component = myComponents.get(componentName)
if (component != null && (component !is PersistentStateComponent<*> || !StoreUtil.getStateSpec(component).reloadable)) {
return false
}
}
return true
}
override fun getNotReloadableComponents(componentNames: Collection<String>): Collection<String> {
var notReloadableComponents: MutableSet<String>? = null
for (componentName in componentNames) {
val component = myComponents.get(componentName)
if (component != null && (component !is PersistentStateComponent<*> || !StoreUtil.getStateSpec(component).reloadable)) {
if (notReloadableComponents == null) {
notReloadableComponents = LinkedHashSet<String>()
}
notReloadableComponents.add(componentName)
}
}
return if (notReloadableComponents == null) emptySet<String>() else notReloadableComponents
}
override fun reinitComponents(componentNames: Set<String>, reloadData: Boolean) {
reinitComponents(componentNames, emptySet<String>(), emptySet<StateStorage>())
}
override fun reinitComponent(componentName: String, changedStorages: Set<StateStorage>): Boolean {
val component = myComponents.get(componentName) as PersistentStateComponent<*>?
if (component == null) {
return false
}
else {
val changedStoragesEmpty = changedStorages.isEmpty()
initPersistentComponent(component, if (changedStoragesEmpty) null else changedStorages, changedStoragesEmpty)
return true
}
}
protected abstract fun getMessageBus(): MessageBus
override fun reload(changedStorages: MultiMap<StateStorage, VirtualFile>): Collection<String>? {
if (changedStorages.isEmpty()) {
return emptySet()
}
val componentNames = SmartHashSet<String>()
for (storage in changedStorages.keySet()) {
try {
// we must update (reload in-memory storage data) even if non-reloadable component will be detected later
// not saved -> user does own modification -> new (on disk) state will be overwritten and not applied
storage.analyzeExternalChangesAndUpdateIfNeed(changedStorages.get(storage), componentNames)
}
catch (e: Throwable) {
LOG.error(e)
}
}
if (componentNames.isEmpty()) {
return emptySet()
}
val notReloadableComponents = getNotReloadableComponents(componentNames)
reinitComponents(componentNames, notReloadableComponents, changedStorages.keySet())
return if (notReloadableComponents.isEmpty()) null else notReloadableComponents
}
// used in settings repository plugin
public fun reinitComponents(componentNames: Set<String>, notReloadableComponents: Collection<String>, changedStorages: Set<StateStorage>) {
val messageBus = getMessageBus()
messageBus.syncPublisher(BatchUpdateListener.TOPIC).onBatchUpdateStarted()
try {
for (componentName in componentNames) {
if (!notReloadableComponents.contains(componentName)) {
reinitComponent(componentName, changedStorages)
}
}
}
finally {
messageBus.syncPublisher(BatchUpdateListener.TOPIC).onBatchUpdateFinished()
}
}
companion object {
private fun findNonDeprecated(storages: Array<Storage>): Storage {
for (storage in storages) {
if (!storage.deprecated) {
return storage
}
}
throw AssertionError("All storages are deprecated")
}
protected fun executeSave(session: SaveSession, readonlyFiles: MutableList<Pair<SaveSession, VirtualFile>>, previousErrors: MutableList<Throwable>?): MutableList<Throwable>? {
var errors = previousErrors
try {
session.save()
}
catch (e: ReadOnlyModificationException) {
LOG.warn(e)
readonlyFiles.add(util.Pair.create<SaveSession, VirtualFile>(if (e.getSession() == null) session else e.getSession(), e.getFile()))
}
catch (e: Exception) {
if (errors == null) {
errors = SmartList<Throwable>()
}
errors.add(e)
}
return errors
}
}
}
@@ -0,0 +1,81 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.configurationStore
import com.intellij.openapi.components.*
import com.intellij.openapi.components.impl.stores.FileBasedStorage
import com.intellij.openapi.components.impl.stores.StateStorageManager
import com.intellij.openapi.components.impl.stores.StreamProvider
import com.intellij.openapi.project.impl.ProjectImpl
import com.intellij.openapi.project.impl.ProjectManagerImpl
import com.intellij.openapi.util.Couple
import com.intellij.util.containers.ContainerUtil
import org.jdom.Element
class DefaultProjectStoreImpl(project: ProjectImpl, private val projectManager: ProjectManagerImpl, pathMacroManager: PathMacroManager) : ProjectStoreImpl(project, pathMacroManager) {
fun getStateCopy(): Element? {
val element = projectManager.getDefaultProjectRootElement()
return element?.clone()
}
override protected fun createStorageManager(): StateStorageManager {
val storage = DefaultProjectStorage(this, pathMacroManager, projectManager)
//noinspection deprecation
return object : StateStorageManager {
override fun addMacro(macro: String, expansion: String) = throw UnsupportedOperationException("Method addMacro not implemented in " + javaClass)
override fun getMacroSubstitutor() = null
override fun getStateStorage(storageSpec: Storage) = storage
override fun getStateStorage(fileSpec: String, roamingType: RoamingType) = storage
override fun getCachedFileStateStorages(changed: Collection<String>, deleted: Collection<String>): Couple<Collection<FileBasedStorage>> = Couple(emptyList<FileBasedStorage>(), emptyList<FileBasedStorage>())
override fun clearStateStorage(file: String) {
}
override fun startExternalization(): StateStorageManager.ExternalizationSession? {
val externalizationSession = storage.startExternalization()
return if (externalizationSession == null) null else MyExternalizationSession(externalizationSession)
}
override fun expandMacros(file: String) = throw UnsupportedOperationException("Method expandMacros not implemented in " + javaClass)
override fun collapseMacros(path: String) = throw UnsupportedOperationException("Method collapseMacros not implemented in " + javaClass)
override fun getOldStorage(component: Any, componentName: String, operation: StateStorageOperation) = storage
override fun setStreamProvider(streamProvider: StreamProvider?) = throw UnsupportedOperationException("Method setStreamProvider not implemented in " + javaClass)
override fun getStreamProvider() = throw UnsupportedOperationException("Method getStreamProviders not implemented in " + javaClass)
override fun getStorageFileNames() = throw UnsupportedOperationException("Method getStorageFileNames not implemented in " + javaClass)
}
}
private class MyExternalizationSession(val externalizationSession: StateStorage.ExternalizationSession) : StateStorageManager.ExternalizationSession {
override fun setState(storageSpecs: Array<Storage>, component: Any, componentName: String, state: Any) {
externalizationSession.setState(component, componentName, state, null)
}
override fun setStateInOldStorage(component: Any, componentName: String, state: Any) {
externalizationSession.setState(component, componentName, state, null)
}
override fun createSaveSessions() = ContainerUtil.createMaybeSingletonList(externalizationSession.createSaveSession())
}
}
@@ -0,0 +1,97 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.configurationStore
import com.intellij.openapi.components.PathMacroSubstitutor
import com.intellij.openapi.components.impl.stores.StorageData
import com.intellij.openapi.module.Module
import com.intellij.openapi.module.OptionManager
import com.intellij.openapi.util.text.StringUtil
import org.jdom.Element
import java.util.TreeMap
class ModuleFileData : ProjectStorageData, OptionManager {
private var options: TreeMap<String, String>? = null
private val module: Module
private var dirty = true
override fun isDirty() = dirty
public constructor(rootElementName: String, module: Module) : super(rootElementName) {
this.module = module
options = TreeMap<String, String>()
}
private constructor(storageData: ModuleFileData) : super(storageData) {
module = storageData.module
dirty = storageData.dirty
options = TreeMap(storageData.options)
}
override fun load(rootElement: Element, pathMacroSubstitutor: PathMacroSubstitutor?, intern: Boolean) {
super<ProjectStorageData>.load(rootElement, pathMacroSubstitutor, intern)
for (attribute in rootElement.getAttributes()) {
val name = attribute.getName()
if (name != ProjectStorageData.VERSION_OPTION && !StringUtil.isEmpty(name)) {
options!!.put(name, attribute.getValue())
}
}
dirty = false
}
override fun writeOptions(root: Element, versionString: String) {
if (!options!!.isEmpty()) {
for (key in options!!.keySet()) {
val value = options!!.get(key)
if (value != null) {
root.setAttribute(key, value)
}
}
}
// need be last for compat reasons
super<ProjectStorageData>.writeOptions(root, versionString)
dirty = false
}
override fun clone() = ModuleFileData(this)
override fun getChangedComponentNames(newStorageData: StorageData, substitutor: PathMacroSubstitutor?): Set<String>? {
val data = newStorageData as ModuleFileData
if (options != data.options) {
return null
}
return super<ProjectStorageData>.getChangedComponentNames(newStorageData, substitutor)
}
override fun setOption(key: String, value: String) {
if (value != options!!.put(key, value)) {
dirty = true
}
}
override fun clearOption(key: String) {
if (options!!.remove(key) != null) {
dirty = true
}
}
override fun getOptionValue(key: String) = options!!.get(key)
}
@@ -0,0 +1,44 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.configurationStore
import com.intellij.openapi.components.StateStorage
import com.intellij.openapi.components.StateStorageOperation
import com.intellij.openapi.components.StoragePathMacros
import com.intellij.openapi.components.TrackingPathMacroSubstitutor
import com.intellij.openapi.module.Module
import com.intellij.util.containers.ContainerUtil
class ModuleStateStorageManager(pathMacroManager: TrackingPathMacroSubstitutor, private val myModule: Module) : StateStorageManagerImpl(pathMacroManager, "module", myModule, myModule.getPicoContainer()) {
override fun createStorageData(fileSpec: String, filePath: String) = ModuleFileData(rootTagName, myModule)
override fun startExternalization() = MyStateStorageManagerExternalizationSession(this)
private class MyStateStorageManagerExternalizationSession(storageManager: StateStorageManagerImpl) : StateStorageManagerImpl.StateStorageManagerExternalizationSession(storageManager) {
override fun createSaveSessions(): List<StateStorage.SaveSession> {
val storage = ContainerUtil.getFirstItem(storageManager.getCachedFileStorages(listOf(StoragePathMacros.MODULE_FILE)))
if (storage != null && storage.getStorageData().isDirty()) {
// force XmlElementStorageSaveSession creation
getExternalizationSession(storage)
}
return super.createSaveSessions()
}
}
override fun getOldStorageSpec(component: Any, componentName: String, operation: StateStorageOperation) = StoragePathMacros.MODULE_FILE
override fun createStorageTopicListener() = myModule.getProject().getMessageBus().syncPublisher(StateStorage.PROJECT_STORAGE_TOPIC)
}
@@ -0,0 +1,30 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.configurationStore
import com.intellij.openapi.components.PathMacroManager
import com.intellij.openapi.module.Module
import com.intellij.openapi.project.ex.ProjectEx
class ModuleStoreImpl(private val myModule: Module, pathMacroManager: PathMacroManager) : BaseFileConfigurableStoreImpl(pathMacroManager) {
override fun getProject() = myModule.getProject()
override fun optimizeTestLoading() = (myModule.getProject() as ProjectEx).isOptimiseTestLoadSpeed()
override fun getMessageBus() = myModule.getMessageBus()
override fun createStorageManager() = ModuleStateStorageManager(pathMacroManager.createTrackingSubstitutor(), myModule)
}
@@ -13,14 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.components.impl.stores;
package com.intellij.configurationStore
import com.intellij.openapi.project.impl.ProjectStoreClassProvider;
import org.jetbrains.annotations.NotNull;
import com.intellij.openapi.components.impl.stores.IComponentStore
import com.intellij.openapi.project.impl.ProjectStoreClassProvider
public class PlatformProjectStoreClassProvider implements ProjectStoreClassProvider {
@NotNull
public Class<? extends IComponentStore> getProjectStoreClass(boolean isDefaultProject) {
return isDefaultProject ? DefaultProjectStoreImpl.class : ProjectStoreImpl.class;
class PlatformProjectStoreClassProvider : ProjectStoreClassProvider {
override fun getProjectStoreClass(isDefaultProject: Boolean): Class<out IComponentStore> {
return if (isDefaultProject) javaClass<DefaultProjectStoreImpl>() else javaClass<ProjectStoreImpl>()
}
}
@@ -0,0 +1,36 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.configurationStore
import com.intellij.openapi.components.*
import com.intellij.openapi.project.impl.ProjectImpl
import org.jdom.Element
class ProjectStateStorageManager(macroSubstitutor: TrackingPathMacroSubstitutor, private val project: ProjectImpl) : StateStorageManagerImpl(macroSubstitutor, "project", project, project.getPicoContainer()) {
override fun createStorageData(fileSpec: String, filePath: String) = ProjectStorageData(rootTagName)
override fun getOldStorageSpec(component: Any, componentName: String, operation: StateStorageOperation): String? {
val workspace = project.isWorkspaceComponent(component.javaClass)
var fileSpec = if (workspace) StoragePathMacros.WORKSPACE_FILE else StoragePathMacros.PROJECT_FILE
val storage = getStateStorage(fileSpec, if (workspace) RoamingType.DISABLED else RoamingType.PER_USER)
if (operation === StateStorageOperation.READ && storage != null && workspace && !storage.hasState(component, componentName, javaClass<Element>(), false)) {
fileSpec = StoragePathMacros.PROJECT_FILE
}
return fileSpec
}
override fun createStorageTopicListener() = project.getMessageBus().syncPublisher(StateStorage.PROJECT_STORAGE_TOPIC)
}
@@ -0,0 +1,376 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.configurationStore
import com.intellij.ide.highlighter.ProjectFileType
import com.intellij.ide.highlighter.WorkspaceFileType
import com.intellij.notification.Notifications
import com.intellij.notification.NotificationsManager
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.ModalityState
import com.intellij.openapi.application.ReadAction
import com.intellij.openapi.components.*
import com.intellij.openapi.components.StateStorage.SaveSession
import com.intellij.openapi.components.impl.stores.*
import com.intellij.openapi.fileTypes.FileTypeManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.impl.ProjectImpl
import com.intellij.openapi.project.impl.ProjectManagerImpl.UnableToSaveProjectNotification
import com.intellij.openapi.util.Pair
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.util.io.FileUtilRt
import com.intellij.openapi.util.text.StringUtil
import com.intellij.openapi.vfs.*
import com.intellij.util.PathUtilRt
import com.intellij.util.SmartList
import com.intellij.util.lang.CompoundRuntimeException
import java.io.BufferedReader
import java.io.File
import java.io.IOException
import java.io.InputStreamReader
import java.util.ArrayList
open class ProjectStoreImpl(protected var myProject: ProjectImpl, pathMacroManager: PathMacroManager) : BaseFileConfigurableStoreImpl(pathMacroManager), IProjectStore {
// protected setter used in upsource
private var scheme = StorageScheme.DEFAULT
protected set
private var presentableUrl: String? = null
override fun getSubstitutors(): Array<TrackingPathMacroSubstitutor> {
val substitutor = getStateStorageManager().getMacroSubstitutor()
return if (substitutor == null) emptyArray() else arrayOf(substitutor)
}
override fun optimizeTestLoading() = myProject.isOptimiseTestLoadSpeed()
override fun getProject() = myProject
override fun setProjectFilePath(filePath: String) {
val stateStorageManager = getStateStorageManager()
val fs = LocalFileSystem.getInstance()
val file = File(filePath)
if (isIprPath(file)) {
scheme = StorageScheme.DEFAULT
stateStorageManager.addMacro(StoragePathMacros.PROJECT_FILE, filePath)
val workspacePath = composeWsPath(filePath)
stateStorageManager.addMacro(StoragePathMacros.WORKSPACE_FILE, workspacePath)
ApplicationManager.getApplication().invokeAndWait(object : Runnable {
override fun run() {
VfsUtil.markDirtyAndRefresh(false, true, false, fs.refreshAndFindFileByPath(filePath), fs.refreshAndFindFileByPath(workspacePath))
}
}, ModalityState.defaultModalityState())
}
else {
scheme = StorageScheme.DIRECTORY_BASED
val dirStore = File(if (file.isDirectory()) file else file.getParentFile(), Project.DIRECTORY_STORE_FOLDER)
stateStorageManager.addMacro(StoragePathMacros.PROJECT_FILE, File(dirStore, "misc.xml").getPath())
stateStorageManager.addMacro(StoragePathMacros.PROJECT_CONFIG_DIR, dirStore.getPath())
val workspace = File(dirStore, "workspace.xml")
stateStorageManager.addMacro(StoragePathMacros.WORKSPACE_FILE, workspace.getPath())
if (!workspace.exists() && !file.isDirectory()) {
useOldWorkspaceContent(filePath, workspace)
}
ApplicationManager.getApplication().invokeAndWait(object : Runnable {
override fun run() {
VfsUtil.markDirtyAndRefresh(false, true, true, fs.refreshAndFindFileByIoFile(dirStore))
}
}, ModalityState.defaultModalityState())
}
presentableUrl = null
}
override fun getProjectBaseDir(): VirtualFile? {
if (myProject.isDefault()) {
return null
}
val path = getProjectBasePath() ?: return null
return LocalFileSystem.getInstance().findFileByPath(path)
}
override fun getProjectBasePath(): String? {
if (myProject.isDefault()) {
return null
}
val path = getProjectFilePath()
if (!StringUtil.isEmptyOrSpaces(path)) {
return getBasePath(File(path))
}
//we are not yet initialized completely ("open directory", etc)
val storage = getStateStorageManager().getStateStorage(StoragePathMacros.PROJECT_FILE, RoamingType.PER_USER)
return if (storage is FileBasedStorage) getBasePath(storage.getFile()) else null
}
private fun getBasePath(file: File) = if (scheme == StorageScheme.DEFAULT) file.getParent() else file.getParentFile()?.getParent()
override fun getProjectName(): String {
if (scheme == StorageScheme.DIRECTORY_BASED) {
val baseDir = getProjectBaseDir()
assert(baseDir != null) { "scheme=$scheme project file=${getProjectFilePath()}" }
val ideaDir = baseDir!!.findChild(Project.DIRECTORY_STORE_FOLDER)
if (ideaDir != null && ideaDir.isValid()) {
val nameFile = ideaDir.findChild(ProjectImpl.NAME_FILE)
if (nameFile != null && nameFile.isValid()) {
try {
val `in` = BufferedReader(InputStreamReader(nameFile.getInputStream(), CharsetToolkit.UTF8_CHARSET))
try {
val name = `in`.readLine()
if (name != null && !name.isEmpty()) {
return name.trim()
}
}
finally {
`in`.close()
}
}
catch (ignored: IOException) {
}
}
}
return baseDir.getName().replace(":", "")
}
else {
var temp = PathUtilRt.getFileName((getProjectFileStorage() as FileBasedStorage).getFilePath())
val fileType = FileTypeManager.getInstance().getFileTypeByFileName(temp)
if (fileType is ProjectFileType) {
temp = temp.substring(0, temp.length() - fileType.getDefaultExtension().length() - 1)
}
val i = temp.lastIndexOf(File.separatorChar)
if (i >= 0) {
temp = temp.substring(i + 1, temp.length() - i + 1)
}
return temp
}
}
override fun getStorageScheme() = scheme
override fun getPresentableUrl(): String? {
if (myProject.isDefault()) {
return null
}
if (presentableUrl == null) {
val url = if (scheme == StorageScheme.DIRECTORY_BASED) getProjectBasePath() else getProjectFilePath()
if (url != null) {
presentableUrl = FileUtil.toSystemDependentName(url)
}
}
return presentableUrl
}
override fun getProjectFile() = if (myProject.isDefault()) null else (getProjectFileStorage() as FileBasedStorage).getVirtualFile()
override fun getProjectFilePath() = if (myProject.isDefault()) "" else (getProjectFileStorage() as FileBasedStorage).getFilePath()
// XmlElementStorage if default project, otherwise FileBasedStorage
private fun getProjectFileStorage() = getStateStorageManager().getStateStorage(StoragePathMacros.PROJECT_FILE, RoamingType.PER_USER) as XmlElementStorage
override fun getWorkspaceFile(): VirtualFile? {
if (myProject.isDefault()) return null
val storage = getStateStorageManager().getStateStorage(StoragePathMacros.WORKSPACE_FILE, RoamingType.DISABLED) as FileBasedStorage?
assert(storage != null)
return storage!!.getVirtualFile()
}
override fun getWorkspaceFilePath(): String? {
if (myProject.isDefault()) {
return null
}
return (getStateStorageManager().getStateStorage(StoragePathMacros.WORKSPACE_FILE, RoamingType.DISABLED) as FileBasedStorage?)!!.getFilePath()
}
override fun loadProjectFromTemplate(defaultProject: ProjectImpl) {
defaultProject.save()
val element = (defaultProject.getStateStore() as DefaultProjectStoreImpl).getStateCopy()
if (element != null) {
getProjectFileStorage().setDefaultState(element)
}
}
override fun createStorageManager(): StateStorageManager = ProjectStateStorageManager(pathMacroManager.createTrackingSubstitutor(), myProject)
override fun doSave(saveSessions: List<SaveSession>?, readonlyFiles: MutableList<Pair<SaveSession, VirtualFile>>, prevErrors: MutableList<Throwable>?): MutableList<Throwable>? {
var errors = prevErrors
beforeSave(readonlyFiles)
super<BaseFileConfigurableStoreImpl>.doSave(saveSessions, readonlyFiles, errors)
val notifications = NotificationsManager.getNotificationsManager().getNotificationsOfType(javaClass<UnableToSaveProjectNotification>(), myProject)
if (readonlyFiles.isEmpty()) {
for (notification in notifications) {
notification.expire()
}
return errors
}
if (!notifications.isEmpty()) {
throw IComponentStore.SaveCancelledException()
}
val status: ReadonlyStatusHandler.OperationStatus
val token = ReadAction.start()
try {
status = ReadonlyStatusHandler.getInstance(myProject).ensureFilesWritable(*getFilesList(readonlyFiles))
}
finally {
token.finish()
}
if (status.hasReadonlyFiles()) {
dropUnableToSaveProjectNotification(myProject, status.getReadonlyFiles())
throw IComponentStore.SaveCancelledException()
}
val oldList = ArrayList(readonlyFiles)
readonlyFiles.clear()
for (entry in oldList) {
errors = ComponentStoreImpl.executeSave(entry.first, readonlyFiles, errors)
}
if (errors != null) {
CompoundRuntimeException.doThrow(errors)
}
if (!readonlyFiles.isEmpty()) {
dropUnableToSaveProjectNotification(myProject, getFilesList(readonlyFiles))
throw IComponentStore.SaveCancelledException()
}
return errors
}
protected open fun beforeSave(readonlyFiles: List<Pair<SaveSession, VirtualFile>>) {
}
private var _defaultStorageChooser: StateStorageChooser<PersistentStateComponent<*>>? = null
override val defaultStorageChooser: StateStorageChooser<PersistentStateComponent<*>>?
get() {
if (_defaultStorageChooser == null) {
_defaultStorageChooser = DefaultStorageChooser(scheme)
}
return _defaultStorageChooser
}
override fun getMessageBus() = myProject.getMessageBus()
override fun <T> getComponentStorageSpecs(component: PersistentStateComponent<T>, stateSpec: State, operation: StateStorageOperation): Array<Storage> {
// if we create project from default, component state written not to own storage file, but to project file,
// we don't have time to fix it properly, so, ancient hack restored.
val result = super<BaseFileConfigurableStoreImpl>.getComponentStorageSpecs(component, stateSpec, operation)
// don't add fake storage if project file storage already listed, otherwise data will be deleted on write (because of "deprecated")
for (storage in result) {
if (storage.file == StoragePathMacros.PROJECT_FILE) {
return result
}
}
return Array(result.size() + 1) { if (it == result.size()) DEFAULT_STORAGE_ANNOTATION else result[it] }
}
companion object {
private val DEFAULT_STORAGE_ANNOTATION = DefaultStorageAnnotation()
private fun isIprPath(file: File) = FileUtilRt.extensionEquals(file.getName(), ProjectFileType.DEFAULT_EXTENSION)
private fun composeWsPath(filePath: String): String {
val lastDot = filePath.lastIndexOf('.')
val filePathWithoutExt = if (lastDot > 0) filePath.substring(0, lastDot) else filePath
return "$filePathWithoutExt${WorkspaceFileType.DOT_DEFAULT_EXTENSION}"
}
private fun useOldWorkspaceContent(filePath: String, ws: File) {
val oldWs = File(composeWsPath(filePath))
if (!oldWs.exists()) {
return
}
try {
FileUtil.copyContent(oldWs, ws)
}
catch (e: IOException) {
LOG.error(e)
}
}
private fun dropUnableToSaveProjectNotification(project: Project, readOnlyFiles: Array<VirtualFile>) {
val notifications = NotificationsManager.getNotificationsManager().getNotificationsOfType(javaClass<UnableToSaveProjectNotification>(), project)
if (notifications.isEmpty()) {
Notifications.Bus.notify(UnableToSaveProjectNotification(project, readOnlyFiles), project)
}
else {
notifications[0].myFiles = readOnlyFiles
}
}
private fun getFilesList(readonlyFiles: List<Pair<SaveSession, VirtualFile>>) = Array(readonlyFiles.size()) { readonlyFiles.get(it).second }
}
}
class DefaultStorageChooser(private val scheme: StorageScheme) : StateStorageChooser<PersistentStateComponent<*>> {
override fun selectStorages(storages: Array<Storage>, component: PersistentStateComponent<*>, operation: StateStorageOperation): Array<Storage> {
if (operation === StateStorageOperation.READ) {
val result = SmartList<Storage>()
for (i in storages.indices.reversed()) {
val storage = storages[i]
if (storage.scheme == scheme) {
result.add(storage)
}
}
for (storage in storages) {
if (storage.scheme == StorageScheme.DEFAULT && !result.contains(storage)) {
result.add(storage)
}
}
return result.toTypedArray()
}
else if (operation == StateStorageOperation.WRITE) {
val result = SmartList<Storage>()
for (storage in storages) {
if (storage.scheme == scheme) {
result.add(storage)
}
}
if (result.isEmpty()) {
for (storage in storages) {
if (storage.scheme == StorageScheme.DEFAULT) {
result.add(storage)
}
}
}
return result.toTypedArray()
}
else {
return emptyArray()
}
}
}
@@ -0,0 +1,85 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.configurationStore
import com.intellij.openapi.components.PathMacroManager
import com.intellij.openapi.components.StateStorage
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
import com.intellij.openapi.module.ModuleManager
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> {
return if (isDefaultProject) javaClass<DefaultProjectStoreImpl>() else javaClass<ProjectWithModulesStoreImpl>()
}
}
class ProjectWithModulesStoreImpl(project: ProjectImpl, pathMacroManager: PathMacroManager) : ProjectStoreImpl(project, pathMacroManager) {
override fun reinitComponent(componentName: String, changedStorages: Set<StateStorage>): Boolean {
if (super.reinitComponent(componentName, changedStorages)) {
return true
}
for (module in getPersistentModules()) {
// we have to reinit all modules for component because we don't know affected module
module.stateStore.reinitComponent(componentName, changedStorages)
}
return true
}
override fun getSubstitutors(): Array<TrackingPathMacroSubstitutor> {
val result = SmartList<TrackingPathMacroSubstitutor>()
ContainerUtil.addIfNotNull(result, getStateStorageManager().getMacroSubstitutor())
for (module in getPersistentModules()) {
ContainerUtil.addIfNotNull(result, module.stateStore.getStateStorageManager().getMacroSubstitutor())
}
return result.toTypedArray()
}
override fun isReloadPossible(componentNames: Set<String>): Boolean {
if (!super.isReloadPossible(componentNames)) {
return false
}
for (module in getPersistentModules()) {
if (!module.stateStore.isReloadPossible(componentNames)) {
return false
}
}
return true
}
private fun getPersistentModules() = ModuleManager.getInstance(myProject)?.getModules() ?: Module.EMPTY_ARRAY
override protected fun beforeSave(readonlyFiles: List<Pair<SaveSession, VirtualFile>>) {
super.beforeSave(readonlyFiles)
for (module in getPersistentModules()) {
module.stateStore.save(readonlyFiles)
}
}
}
@@ -26,7 +26,6 @@ import com.intellij.openapi.components.impl.stores.DirectoryStorageData
import com.intellij.openapi.components.impl.stores.StorageUtil
import com.intellij.openapi.components.impl.stores.StreamProvider
import com.intellij.openapi.components.service
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.extensions.AbstractExtensionPointBean
import com.intellij.openapi.options.*
import com.intellij.openapi.util.Comparing
@@ -54,8 +53,6 @@ import java.io.InputStream
import java.util.ArrayList
import java.util.Collections
private val LOG = Logger.getInstance(javaClass<SchemeManagerImpl<*, *>>())
public class SchemeManagerImpl<T : Scheme, E : ExternalizableScheme>(private val fileSpec: String,
private val processor: SchemeProcessor<E>,
private val roamingType: RoamingType,
@@ -0,0 +1,258 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.configurationStore
import com.intellij.openapi.Disposable
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.*
import com.intellij.openapi.components.StateStorage.SaveSession
import com.intellij.openapi.components.StateStorageChooserEx.Resolution
import com.intellij.openapi.components.impl.stores.*
import com.intellij.openapi.util.Couple
import com.intellij.openapi.util.Disposer
import com.intellij.openapi.util.text.StringUtil
import com.intellij.util.PathUtilRt
import com.intellij.util.ReflectionUtil
import com.intellij.util.SmartList
import com.intellij.util.containers.ContainerUtil
import gnu.trove.THashMap
import org.jdom.Element
import org.picocontainer.MutablePicoContainer
import org.picocontainer.PicoContainer
import java.io.File
import java.util.LinkedHashMap
import java.util.UUID
import java.util.concurrent.locks.ReentrantLock
import java.util.regex.Pattern
import kotlin.concurrent.withLock
import kotlin.reflect.jvm.java
abstract class StateStorageManagerImpl(private val pathMacroSubstitutor: TrackingPathMacroSubstitutor, protected val rootTagName: String, parentDisposable: Disposable, private val picoContainer: PicoContainer) : StateStorageManager, Disposable {
private val macros = LinkedHashMap<String, String>()
private val storageLock = ReentrantLock()
private val storages = THashMap<String, StateStorage>()
private var streamProvider: StreamProvider? = null
init {
Disposer.register(parentDisposable, this)
}
companion object {
private val MACRO_PATTERN = Pattern.compile("(\\$[^\\$]*\\$)")
}
override fun getStreamProvider() = streamProvider
override fun setStreamProvider(value: StreamProvider?) {
streamProvider = value
}
override fun getMacroSubstitutor() = pathMacroSubstitutor
synchronized override fun addMacro(macro: String, expansion: String) {
assert(!macro.isEmpty())
macros.put(macro, expansion)
}
override fun getStateStorage(storageSpec: Storage): StateStorage {
@suppress("USELESS_CAST")
val storageClass = storageSpec.storageClass.java as Class<out StateStorage>
val key = if (storageClass == javaClass<StateStorage>()) storageSpec.file else storageClass.getName()
storageLock.withLock {
var stateStorage: StateStorage? = storages.get(key)
if (stateStorage == null) {
stateStorage = createStateStorage(storageClass, storageSpec.file, storageSpec.roamingType, storageSpec.stateSplitter.java)
storages.put(key, stateStorage)
}
return stateStorage
}
}
override fun getStateStorage(fileSpec: String, roamingType: RoamingType): StateStorage? {
storageLock.withLock {
var stateStorage: StateStorage? = storages.get(fileSpec)
if (stateStorage == null) {
stateStorage = createStateStorage(javaClass<StateStorage>(), fileSpec, roamingType, javaClass<StateSplitterEx>())
storages.put(fileSpec, stateStorage)
}
return stateStorage
}
}
override fun getCachedFileStateStorages(changed: Collection<String>, deleted: Collection<String>) = storageLock.withLock { Couple.of(getCachedFileStorages(changed), getCachedFileStorages(deleted)) }
fun getCachedFileStorages(fileSpecs: Collection<String>): Collection<FileBasedStorage> {
if (fileSpecs.isEmpty()) {
return emptyList()
}
var result: MutableList<FileBasedStorage>? = null
for (fileSpec in fileSpecs) {
val storage = storages.get(fileSpec)
if (storage is FileBasedStorage) {
if (result == null) {
result = SmartList<FileBasedStorage>()
}
result.add(storage)
}
}
return result ?: emptyList<FileBasedStorage>()
}
override fun getStorageFileNames() = storageLock.withLock { storages.keySet() }
// overridden in upsource
protected fun createStateStorage(storageClass: Class<out StateStorage>, fileSpec: String, roamingType: RoamingType, SuppressWarnings("deprecation") stateSplitter: Class<out StateSplitter>): StateStorage {
if (storageClass != javaClass<StateStorage>()) {
val key = UUID.randomUUID().toString()
(picoContainer as MutablePicoContainer).registerComponentImplementation(key, storageClass)
return picoContainer.getComponentInstance(key) as StateStorage
}
val filePath = expandMacros(fileSpec)
val file = File(filePath)
//noinspection deprecation
if (stateSplitter != javaClass<StateSplitter>() && stateSplitter != javaClass<StateSplitterEx>()) {
return DirectoryBasedStorage(pathMacroSubstitutor, file, ReflectionUtil.newInstance(stateSplitter), this, createStorageTopicListener())
}
if (!ApplicationManager.getApplication().isHeadlessEnvironment() && PathUtilRt.getFileName(filePath).lastIndexOf('.') < 0) {
throw IllegalArgumentException("Extension is missing for storage file: " + filePath)
}
val effectiveRoamingType = if (roamingType == RoamingType.PER_USER && fileSpec == StoragePathMacros.WORKSPACE_FILE) RoamingType.DISABLED else roamingType
beforeFileBasedStorageCreate()
return object : FileBasedStorage(file, fileSpec, effectiveRoamingType, getMacroSubstitutor(fileSpec), rootTagName, this@StateStorageManagerImpl, createStorageTopicListener(), streamProvider) {
override fun createStorageData() = this@StateStorageManagerImpl.createStorageData(myFileSpec, getFilePath())
override fun isUseXmlProlog() = this@StateStorageManagerImpl.isUseXmlProlog()
}
}
override fun clearStateStorage(file: String) {
storageLock.withLock { storages.remove(file) }
}
protected open fun createStorageTopicListener(): StateStorage.Listener? = null
protected open fun isUseXmlProlog(): Boolean = true
protected open fun beforeFileBasedStorageCreate() {
}
protected open fun getMacroSubstitutor(fileSpec: String): TrackingPathMacroSubstitutor? = pathMacroSubstitutor
protected abstract fun createStorageData(fileSpec: String, filePath: String): StorageData
synchronized override fun expandMacros(file: String): String {
val matcher = MACRO_PATTERN.matcher(file)
while (matcher.find()) {
val m = matcher.group(1)
if (!macros.containsKey(m)) {
throw IllegalArgumentException("Unknown macro: " + m + " in storage file spec: " + file)
}
}
var expanded = file
for (entry in macros.entrySet()) {
expanded = StringUtil.replace(expanded, entry.getKey(), entry.getValue())
}
return expanded
}
override fun collapseMacros(path: String): String {
var result = path
for (entry in macros.entrySet()) {
result = StringUtil.replace(result, entry.getValue(), entry.getKey())
}
return result
}
override fun startExternalization() = StateStorageManagerExternalizationSession(this)
open class StateStorageManagerExternalizationSession(protected val storageManager: StateStorageManagerImpl) : StateStorageManager.ExternalizationSession {
private val mySessions = LinkedHashMap<StateStorage, StateStorage.ExternalizationSession>()
override fun setState(storageSpecs: Array<Storage>, component: Any, componentName: String, state: Any) {
val stateStorageChooser = if (component is StateStorageChooserEx) component else null
for (storageSpec in storageSpecs) {
val resolution = if (stateStorageChooser == null) Resolution.DO else stateStorageChooser.getResolution(storageSpec, StateStorageOperation.WRITE)
if (resolution === Resolution.SKIP) {
continue
}
val stateStorage = storageManager.getStateStorage(storageSpec)
val session = getExternalizationSession(stateStorage)
session?.setState(component, componentName, if (storageSpec.deprecated || resolution === Resolution.CLEAR) Element("empty") else state, storageSpec)
}
}
override fun setStateInOldStorage(component: Any, componentName: String, state: Any) {
val stateStorage = storageManager.getOldStorage(component, componentName, StateStorageOperation.WRITE)
if (stateStorage != null) {
val session = getExternalizationSession(stateStorage)
session?.setState(component, componentName, state, null)
}
}
protected fun getExternalizationSession(stateStorage: StateStorage): StateStorage.ExternalizationSession? {
var session: StateStorage.ExternalizationSession? = mySessions.get(stateStorage)
if (session == null) {
session = stateStorage.startExternalization()
if (session != null) {
mySessions.put(stateStorage, session)
}
}
return session
}
override fun createSaveSessions(): List<SaveSession> {
if (mySessions.isEmpty()) {
return emptyList()
}
var saveSessions: MutableList<SaveSession>? = null
val externalizationSessions = mySessions.values()
for (session in externalizationSessions) {
val saveSession = session.createSaveSession()
if (saveSession != null) {
if (saveSessions == null) {
if (externalizationSessions.size() == 1) {
return listOf(saveSession)
}
saveSessions = SmartList<SaveSession>()
}
saveSessions.add(saveSession)
}
}
return ContainerUtil.notNullize(saveSessions)
}
}
override fun getOldStorage(component: Any, componentName: String, operation: StateStorageOperation): StateStorage? {
val oldStorageSpec = getOldStorageSpec(component, componentName, operation)
@suppress("DEPRECATED_SYMBOL_WITH_MESSAGE")
return if (oldStorageSpec == null) null else getStateStorage(oldStorageSpec, if (component is com.intellij.openapi.util.RoamingTypeDisabled) RoamingType.DISABLED else RoamingType.PER_USER)
}
protected abstract fun getOldStorageSpec(component: Any, componentName: String, operation: StateStorageOperation): String?
override fun dispose() {
}
}
@@ -0,0 +1,54 @@
package com.intellij.configurationStore;
import com.intellij.openapi.components.PathMacroManager;
import com.intellij.openapi.components.RoamingType;
import com.intellij.openapi.components.impl.stores.StorageData;
import com.intellij.openapi.components.impl.stores.XmlElementStorage;
import com.intellij.openapi.project.impl.ProjectManagerImpl;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class DefaultProjectStorage extends XmlElementStorage {
private final DefaultProjectStoreImpl store;
private final ProjectManagerImpl projectManager;
public DefaultProjectStorage(DefaultProjectStoreImpl store, PathMacroManager pathMacroManager, ProjectManagerImpl projectManager) {
super("", RoamingType.DISABLED, pathMacroManager.createTrackingSubstitutor(), "defaultProject", null);
this.store = store;
this.projectManager = projectManager;
}
@Override
@Nullable
protected Element loadLocalData() {
return store.getStateCopy();
}
@NotNull
@Override
protected XmlElementStorageSaveSession createSaveSession(@NotNull StorageData storageData) {
return new XmlElementStorageSaveSession(storageData) {
@Override
protected void doSave(@Nullable Element element) {
// we must set empty element instead of null as indicator - ProjectManager state is ready to save
projectManager.setDefaultProjectRootElement(element == null ? new Element("empty") : element);
}
// we must not collapse paths here, because our solution is just a big hack
// by default, getElementToSave() returns collapsed paths -> setDefaultProjectRootElement -> project manager writeExternal -> save -> compare old and new - diff because old has expanded, but new collapsed
// -> needless save
@Override
protected boolean isCollapsePathsOnSave() {
return false;
}
};
}
@Override
@NotNull
protected StorageData createStorageData() {
return new StorageData(myRootElementName);
}
}
@@ -0,0 +1,55 @@
package com.intellij.configurationStore;
import com.intellij.openapi.components.*;
import org.jetbrains.annotations.NotNull;
import java.lang.annotation.Annotation;
@SuppressWarnings("ClassExplicitlyAnnotation")
public final class DefaultStorageAnnotation implements Storage {
@Override
public String id() {
return "___Default___";
}
@Override
public boolean isDefault() {
return true;
}
@Override
public String file() {
return StoragePathMacros.PROJECT_FILE;
}
@Override
public StorageScheme scheme() {
return StorageScheme.DEFAULT;
}
@Override
public boolean deprecated() {
return true;
}
@Override
public RoamingType roamingType() {
return RoamingType.PER_USER;
}
@Override
public Class<? extends StateStorage> storageClass() {
return StateStorage.class;
}
@Override
public Class<StateSplitterEx> stateSplitter() {
return StateSplitterEx.class;
}
@NotNull
@Override
public Class<? extends Annotation> annotationType() {
throw new UnsupportedOperationException("Method annotationType not implemented in " + getClass());
}
}
@@ -1,25 +0,0 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.components.impl;
/**
* @author mike
*/
public class ApplicationPathMacroManager extends BasePathMacroManager {
public ApplicationPathMacroManager() {
super(null);
}
}
@@ -1,113 +0,0 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.components.impl.stores;
import com.intellij.application.options.PathMacrosImpl;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.application.impl.ApplicationImpl;
import com.intellij.openapi.components.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.NamedJDOMExternalizable;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.messages.MessageBus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
class ApplicationStoreImpl extends ComponentStoreImpl {
private static final Logger LOG = Logger.getInstance(ApplicationStoreImpl.class);
private static final String DEFAULT_STORAGE_SPEC = StoragePathMacros.APP_CONFIG + "/" + PathManager.DEFAULT_OPTIONS_FILE_NAME + DirectoryStorageData.DEFAULT_EXT;
private static final String ROOT_ELEMENT_NAME = "application";
private final ApplicationImpl myApplication;
private final StateStorageManager myStateStorageManager;
public ApplicationStoreImpl(@NotNull ApplicationImpl application, @NotNull PathMacroManager pathMacroManager) {
myApplication = application;
myStateStorageManager = new StateStorageManagerImpl(pathMacroManager.createTrackingSubstitutor(), ROOT_ELEMENT_NAME, application, application.getPicoContainer()) {
private boolean myConfigDirectoryRefreshed;
@Nullable
protected StateStorage.Listener createStorageTopicListener() {
return myApplication.getMessageBus().syncPublisher(StateStorage.STORAGE_TOPIC);
}
@NotNull
@Override
protected StorageData createStorageData(@NotNull String fileSpec, @NotNull String filePath) {
return new StorageData(ROOT_ELEMENT_NAME);
}
@Nullable
@Override
protected String getOldStorageSpec(@NotNull Object component, @NotNull String componentName, @NotNull StateStorageOperation operation) {
if (component instanceof NamedJDOMExternalizable) {
return StoragePathMacros.APP_CONFIG + '/' + ((NamedJDOMExternalizable)component).getExternalFileName() + DirectoryStorageData.DEFAULT_EXT;
}
else {
return DEFAULT_STORAGE_SPEC;
}
}
@Override
protected TrackingPathMacroSubstitutor getMacroSubstitutor(@NotNull String fileSpec) {
return fileSpec.equals(StoragePathMacros.APP_CONFIG + '/' + PathMacrosImpl.EXT_FILE_NAME + DirectoryStorageData.DEFAULT_EXT) ? null : super.getMacroSubstitutor(fileSpec);
}
@Override
protected boolean isUseXmlProlog() {
return false;
}
@Override
protected void beforeFileBasedStorageCreate() {
if (myConfigDirectoryRefreshed || (!myApplication.isUnitTestMode() && !myApplication.isDispatchThread())) {
return;
}
try {
String configPath = getMacrosValue(StoragePathMacros.ROOT_CONFIG);
if (configPath == null) {
LOG.warn("Macros ROOT_CONFIG is not defined");
return;
}
VirtualFile configDir = LocalFileSystem.getInstance().refreshAndFindFileByPath(configPath);
if (configDir != null) {
VfsUtil.markDirtyAndRefresh(false, true, true, configDir);
}
}
finally {
myConfigDirectoryRefreshed = true;
}
}
};
}
@Override
@NotNull
protected MessageBus getMessageBus() {
return myApplication.getMessageBus();
}
@NotNull
@Override
public StateStorageManager getStateStorageManager() {
return myStateStorageManager;
}
}
@@ -1,116 +0,0 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.components.impl.stores;
import com.intellij.openapi.components.PathMacroManager;
import com.intellij.openapi.components.PathMacroSubstitutor;
import com.intellij.openapi.project.impl.ProjectManagerImpl;
import com.intellij.util.SmartList;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Map;
import java.util.Set;
abstract class BaseFileConfigurableStoreImpl extends ComponentStoreImpl {
@NonNls protected static final String VERSION_OPTION = "version";
@NonNls public static final String ATTRIBUTE_NAME = "name";
private static final List<String> ourConversionProblemsStorage = new SmartList<String>();
private StateStorageManager myStateStorageManager;
protected final PathMacroManager myPathMacroManager;
protected BaseFileConfigurableStoreImpl(@NotNull PathMacroManager pathMacroManager) {
myPathMacroManager = pathMacroManager;
}
protected static class BaseStorageData extends StorageData {
private int myVersion = ProjectManagerImpl.CURRENT_FORMAT_VERSION;
public BaseStorageData(@NotNull String rootElementName) {
super(rootElementName);
}
protected BaseStorageData(BaseStorageData storageData) {
super(storageData);
}
@Override
public void load(@NotNull Element rootElement, @Nullable PathMacroSubstitutor pathMacroSubstitutor, boolean intern) {
super.load(rootElement, pathMacroSubstitutor, intern);
String v = rootElement.getAttributeValue(VERSION_OPTION);
myVersion = v == null ? ProjectManagerImpl.CURRENT_FORMAT_VERSION : Integer.parseInt(v);
}
@Override
@NotNull
protected final Element save(@NotNull Map<String, Element> newLiveStates) {
Element root = super.save(newLiveStates);
if (root == null) {
root = new Element(myRootElementName);
}
writeOptions(root, Integer.toString(myVersion));
return root;
}
protected void writeOptions(@NotNull Element root, @NotNull String versionString) {
root.setAttribute(VERSION_OPTION, versionString);
}
@Override
public StorageData clone() {
return new BaseStorageData(this);
}
@Nullable
@Override
public Set<String> getChangedComponentNames(@NotNull StorageData newStorageData, @Nullable PathMacroSubstitutor substitutor) {
BaseStorageData data = (BaseStorageData)newStorageData;
if (myVersion != data.myVersion) {
return null;
}
return super.getChangedComponentNames(newStorageData, substitutor);
}
}
@Nullable
static List<String> getConversionProblemsStorage() {
return ourConversionProblemsStorage;
}
@NotNull
@Override
protected final PathMacroManager getPathMacroManagerForDefaults() {
return myPathMacroManager;
}
@NotNull
@Override
public final StateStorageManager getStateStorageManager() {
if (myStateStorageManager == null) {
myStateStorageManager = createStateStorageManager();
}
return myStateStorageManager;
}
@NotNull
protected abstract StateStorageManager createStateStorageManager();
}
@@ -1,529 +0,0 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.components.impl.stores;
import com.intellij.openapi.application.*;
import com.intellij.openapi.application.ex.DecodeDefaultsUtil;
import com.intellij.openapi.components.*;
import com.intellij.openapi.components.StateStorage.SaveSession;
import com.intellij.openapi.components.StateStorageChooserEx.Resolution;
import com.intellij.openapi.components.impl.ComponentManagerImpl;
import com.intellij.openapi.components.impl.stores.StateStorageManager.ExternalizationSession;
import com.intellij.openapi.components.store.ReadOnlyModificationException;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.*;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess;
import com.intellij.util.ArrayUtilRt;
import com.intellij.util.ReflectionUtil;
import com.intellij.util.SmartList;
import com.intellij.util.containers.MultiMap;
import com.intellij.util.containers.SmartHashSet;
import com.intellij.util.lang.CompoundRuntimeException;
import com.intellij.util.messages.MessageBus;
import com.intellij.util.xmlb.JDOMXIncluder;
import gnu.trove.THashMap;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
@SuppressWarnings({"deprecation"})
public abstract class ComponentStoreImpl implements IComponentStore {
private static final Logger LOG = Logger.getInstance(ComponentStoreImpl.class);
private final Map<String, Object> myComponents = Collections.synchronizedMap(new THashMap<String, Object>());
private final List<SettingsSavingComponent> mySettingsSavingComponents = new CopyOnWriteArrayList<SettingsSavingComponent>();
@Override
public void initComponent(@NotNull Object component, boolean service) {
if (component instanceof SettingsSavingComponent) {
mySettingsSavingComponents.add((SettingsSavingComponent)component);
}
if (!(component instanceof JDOMExternalizable || component instanceof PersistentStateComponent)) {
return;
}
AccessToken token = ReadAction.start();
try {
String componentNameIfStateExists;
if (component instanceof PersistentStateComponent) {
componentNameIfStateExists = initPersistentComponent((PersistentStateComponent<?>)component, null, false);
}
else {
componentNameIfStateExists = initJdomExternalizable((JDOMExternalizable)component);
}
// if not service, so, component manager will check it later for all components
if (componentNameIfStateExists != null && service) {
Project project = getProject();
Application app = ApplicationManager.getApplication();
if (project != null && !app.isHeadlessEnvironment() && !app.isUnitTestMode() && project.isInitialized()) {
TrackingPathMacroSubstitutor substitutor = getStateStorageManager().getMacroSubstitutor();
if (substitutor != null) {
StorageUtil.notifyUnknownMacros(substitutor, project, componentNameIfStateExists);
}
}
}
}
catch (StateStorageException e) {
throw e;
}
catch (ProcessCanceledException e) {
throw e;
}
catch (Exception e) {
LOG.error(e);
}
finally {
token.finish();
}
}
@Override
public final void save(@NotNull List<Pair<StateStorage.SaveSession, VirtualFile>> readonlyFiles) {
ExternalizationSession externalizationSession = myComponents.isEmpty() ? null : getStateStorageManager().startExternalization();
if (externalizationSession != null) {
String[] names = ArrayUtilRt.toStringArray(myComponents.keySet());
Arrays.sort(names);
for (String name : names) {
commitComponent(externalizationSession, myComponents.get(name), name);
}
}
List<Throwable> errors = null;
for (SettingsSavingComponent settingsSavingComponent : mySettingsSavingComponents) {
try {
settingsSavingComponent.save();
}
catch (Throwable e) {
if (errors == null) {
errors = new SmartList<Throwable>();
}
errors.add(e);
}
}
errors = doSave(externalizationSession == null ? null : externalizationSession.createSaveSessions(), readonlyFiles, errors);
CompoundRuntimeException.doThrow(errors);
}
@TestOnly
@Override
public void saveApplicationComponent(@NotNull Object component) {
StateStorageManager.ExternalizationSession externalizationSession = getStateStorageManager().startExternalization();
if (externalizationSession == null) {
return;
}
commitComponent(externalizationSession, component, null);
List<SaveSession> sessions = externalizationSession.createSaveSessions();
if (sessions.isEmpty()) {
return;
}
final File file;
State state = StoreUtil.getStateSpec(component.getClass());
if (state != null) {
file = new File(getStateStorageManager().expandMacros(findNonDeprecated(state.storages()).file()));
}
else if (component instanceof ExportableApplicationComponent && component instanceof NamedJDOMExternalizable) {
file = PathManager.getOptionsFile((NamedJDOMExternalizable)component);
}
else {
throw new AssertionError(component.getClass() + " doesn't have @State annotation and doesn't implement ExportableApplicationComponent");
}
AccessToken token = WriteAction.start();
try {
VfsRootAccess.allowRootAccess(file.getAbsolutePath());
CompoundRuntimeException.doThrow(doSave(sessions, Collections.<Pair<SaveSession, VirtualFile>>emptyList(), null));
}
finally {
try {
VfsRootAccess.disallowRootAccess(file.getAbsolutePath());
}
finally {
token.finish();
}
}
}
private static Storage findNonDeprecated(Storage[] storages) {
for (Storage storage : storages) {
if (!storage.deprecated()) {
return storage;
}
}
throw new AssertionError("All storages are deprecated");
}
private void commitComponent(@NotNull ExternalizationSession externalizationSession, @NotNull Object component, @Nullable String componentName) {
if (component instanceof PersistentStateComponent) {
commitPersistentComponent((PersistentStateComponent<?>)component, externalizationSession, componentName);
}
else if (component instanceof JDOMExternalizable) {
externalizationSession.setStateInOldStorage(component, componentName == null ? ComponentManagerImpl.getComponentName(component) : componentName, component);
}
}
@Nullable
protected List<Throwable> doSave(@Nullable List<SaveSession> saveSessions, @NotNull List<Pair<SaveSession, VirtualFile>> readonlyFiles, @Nullable List<Throwable> errors) {
if (saveSessions != null) {
for (SaveSession session : saveSessions) {
errors = executeSave(session, readonlyFiles, errors);
}
}
return errors;
}
@Nullable
protected static List<Throwable> executeSave(@NotNull SaveSession session, @NotNull List<Pair<SaveSession, VirtualFile>> readonlyFiles, @Nullable List<Throwable> errors) {
try {
session.save();
}
catch (ReadOnlyModificationException e) {
LOG.warn(e);
readonlyFiles.add(Pair.create(e.getSession() == null ? session : e.getSession(), e.getFile()));
}
catch (Exception e) {
if (errors == null) {
errors = new SmartList<Throwable>();
}
errors.add(e);
}
return errors;
}
private <T> void commitPersistentComponent(@NotNull PersistentStateComponent<T> component, @NotNull ExternalizationSession session, @Nullable String componentName) {
T state = component.getState();
if (state != null) {
Storage[] storageSpecs = getComponentStorageSpecs(component, StoreUtil.getStateSpec(component), StateStorageOperation.WRITE);
session.setState(storageSpecs, component, componentName == null ? StoreUtil.getComponentName(component) : componentName, state);
}
}
@Nullable
private String initJdomExternalizable(@NotNull JDOMExternalizable component) {
String componentName = ComponentManagerImpl.getComponentName(component);
doAddComponent(componentName, component);
if (optimizeTestLoading()) {
return null;
}
loadJdomDefaults(component, componentName);
StateStorage stateStorage = getStateStorageManager().getOldStorage(component, componentName, StateStorageOperation.READ);
if (stateStorage == null) {
return null;
}
Element element = stateStorage.getState(component, componentName, Element.class, null);
if (element == null) {
return null;
}
try {
if (LOG.isDebugEnabled()) {
LOG.debug("Loading configuration for " + component.getClass());
}
component.readExternal(element);
}
catch (InvalidDataException e) {
LOG.error(e);
return null;
}
return componentName;
}
private void doAddComponent(String componentName, Object component) {
Object existing = myComponents.get(componentName);
if (existing != null && existing != component) {
LOG.error("Conflicting component name '" + componentName + "': " + existing.getClass() + " and " + component.getClass());
}
myComponents.put(componentName, component);
}
private void loadJdomDefaults(@NotNull JDOMExternalizable component, @NotNull String componentName) {
try {
Element defaultState = getDefaultState(component, componentName, Element.class);
if (defaultState != null) {
component.readExternal(defaultState);
}
}
catch (Exception e) {
LOG.error("Cannot load defaults for " + component.getClass(), e);
}
}
@Nullable
protected Project getProject() {
return null;
}
@Nullable
private <T> String initPersistentComponent(@NotNull PersistentStateComponent<T> component, @Nullable Set<StateStorage> changedStorages, boolean reloadData) {
State stateSpec = StoreUtil.getStateSpec(component);
String name = stateSpec.name();
if (changedStorages == null || !reloadData) {
doAddComponent(name, component);
}
if (optimizeTestLoading()) {
return null;
}
Class<T> stateClass = ComponentSerializationUtil.getStateClass(component.getClass());
if (!stateSpec.defaultStateAsResource() && LOG.isDebugEnabled() && getDefaultState(component, name, stateClass) != null) {
LOG.error(name + " has default state, but not marked to load it");
}
T state = stateSpec.defaultStateAsResource() ? getDefaultState(component, name, stateClass) : null;
Storage[] storageSpecs = getComponentStorageSpecs(component, stateSpec, StateStorageOperation.READ);
StateStorageChooserEx stateStorageChooser = component instanceof StateStorageChooserEx ? (StateStorageChooserEx)component : null;
for (Storage storageSpec : storageSpecs) {
Resolution resolution = stateStorageChooser == null ? Resolution.DO : stateStorageChooser.getResolution(storageSpec, StateStorageOperation.READ);
if (resolution == Resolution.SKIP) {
continue;
}
StateStorage stateStorage = getStateStorageManager().getStateStorage(storageSpec);
boolean forcedState = false;
if (stateStorage != null && (stateStorage.hasState(component, name, stateClass, reloadData) ||
(forcedState = changedStorages != null && changedStorages.contains(stateStorage)))) {
state = stateStorage.getState(component, name, stateClass, state);
if (state == null && forcedState) {
// state will be null if file deleted
// we must create empty (initial) state to reinit component
state = DefaultStateSerializer.deserializeState(new Element("state"), stateClass, null);
}
break;
}
}
if (state != null) {
component.loadState(state);
}
return name;
}
@Nullable
protected PathMacroManager getPathMacroManagerForDefaults() {
return null;
}
@Nullable
protected <T> T getDefaultState(@NotNull Object component, @NotNull String componentName, @NotNull final Class<T> stateClass) {
URL url = DecodeDefaultsUtil.getDefaults(component, componentName);
if (url == null) {
return null;
}
try {
Element documentElement = JDOMXIncluder.resolve(JDOMUtil.loadDocument(url), url.toExternalForm()).detachRootElement();
PathMacroManager pathMacroManager = getPathMacroManagerForDefaults();
if (pathMacroManager != null) {
pathMacroManager.expandPaths(documentElement);
}
return DefaultStateSerializer.deserializeState(documentElement, stateClass, null);
}
catch (IOException e) {
throw new StateStorageException("Error loading state from " + url, e);
}
catch (JDOMException e) {
throw new StateStorageException("Error loading state from " + url, e);
}
}
@NotNull
protected <T> Storage[] getComponentStorageSpecs(@NotNull PersistentStateComponent<T> component,
@NotNull State stateSpec,
@NotNull StateStorageOperation operation) {
Storage[] storages = stateSpec.storages();
if (storages.length == 1) {
return storages;
}
assert storages.length > 0;
StateStorageChooser<PersistentStateComponent<T>> storageChooser;
Class<? extends StateStorageChooser> storageChooserClass = stateSpec.storageChooser();
if (storageChooserClass != StateStorageChooser.class) {
//noinspection unchecked
storageChooser = ReflectionUtil.newInstance(storageChooserClass);
return storageChooser.selectStorages(storages, component, operation);
}
StateStorageChooser<PersistentStateComponent<?>> defaultStateStorageChooser = getDefaultStateStorageChooser();
if (defaultStateStorageChooser != null) {
return defaultStateStorageChooser.selectStorages(storages, component, operation);
}
if (component instanceof StateStorageChooserEx) {
return storages;
}
int actualStorageCount = 0;
for (Storage storage : storages) {
if (!storage.deprecated()) {
actualStorageCount++;
}
}
if (actualStorageCount > 1) {
LOG.error("State chooser not specified for: " + component.getClass());
}
if (!storages[0].deprecated()) {
boolean othersAreDeprecated = true;
for (int i = 1; i < storages.length; i++) {
if (!storages[i].deprecated()) {
othersAreDeprecated = false;
break;
}
}
if (othersAreDeprecated) {
return storages;
}
}
Storage[] sorted = Arrays.copyOf(storages, storages.length);
Arrays.sort(sorted, new Comparator<Storage>() {
@Override
public int compare(Storage o1, Storage o2) {
int w1 = o1.deprecated() ? 1 : 0;
int w2 = o2.deprecated() ? 1 : 0;
return w1 - w2;
}
});
return sorted;
}
protected boolean optimizeTestLoading() {
return false;
}
@Nullable
protected StateStorageChooser<PersistentStateComponent<?>> getDefaultStateStorageChooser() {
return null;
}
@Override
public boolean isReloadPossible(@NotNull final Set<String> componentNames) {
for (String componentName : componentNames) {
final Object component = myComponents.get(componentName);
if (component != null && (!(component instanceof PersistentStateComponent) || !StoreUtil.getStateSpec((PersistentStateComponent<?>)component).reloadable())) {
return false;
}
}
return true;
}
@Override
@NotNull
public final Collection<String> getNotReloadableComponents(@NotNull Collection<String> componentNames) {
Set<String> notReloadableComponents = null;
for (String componentName : componentNames) {
Object component = myComponents.get(componentName);
if (component != null && (!(component instanceof PersistentStateComponent) || !StoreUtil.getStateSpec((PersistentStateComponent<?>)component).reloadable())) {
if (notReloadableComponents == null) {
notReloadableComponents = new LinkedHashSet<String>();
}
notReloadableComponents.add(componentName);
}
}
return notReloadableComponents == null ? Collections.<String>emptySet() : notReloadableComponents;
}
@Override
public void reinitComponents(@NotNull Set<String> componentNames, boolean reloadData) {
reinitComponents(componentNames, Collections.<String>emptySet(), Collections.<StateStorage>emptySet());
}
@Override
public boolean reinitComponent(@NotNull String componentName, @NotNull Set<StateStorage> changedStorages) {
PersistentStateComponent component = (PersistentStateComponent)myComponents.get(componentName);
if (component == null) {
return false;
}
else {
boolean changedStoragesEmpty = changedStorages.isEmpty();
initPersistentComponent(component, changedStoragesEmpty ? null : changedStorages, changedStoragesEmpty);
return true;
}
}
@NotNull
protected abstract MessageBus getMessageBus();
@Override
@Nullable
public final Collection<String> reload(@NotNull MultiMap<StateStorage, VirtualFile> changedStorages) {
if (changedStorages.isEmpty()) {
return Collections.emptySet();
}
Set<String> componentNames = new SmartHashSet<String>();
for (StateStorage storage : changedStorages.keySet()) {
try {
// we must update (reload in-memory storage data) even if non-reloadable component will be detected later
// not saved -> user does own modification -> new (on disk) state will be overwritten and not applied
storage.analyzeExternalChangesAndUpdateIfNeed(changedStorages.get(storage), componentNames);
}
catch (Throwable e) {
LOG.error(e);
}
}
if (componentNames.isEmpty()) {
return Collections.emptySet();
}
Collection<String> notReloadableComponents = getNotReloadableComponents(componentNames);
reinitComponents(componentNames, notReloadableComponents, changedStorages.keySet());
return notReloadableComponents.isEmpty() ? null : notReloadableComponents;
}
// used in settings repository plugin
public void reinitComponents(@NotNull Set<String> componentNames, @NotNull Collection<String> notReloadableComponents, @NotNull Set<StateStorage> changedStorages) {
MessageBus messageBus = getMessageBus();
messageBus.syncPublisher(BatchUpdateListener.TOPIC).onBatchUpdateStarted();
try {
for (String componentName : componentNames) {
if (!notReloadableComponents.contains(componentName)) {
reinitComponent(componentName, changedStorages);
}
}
}
finally {
messageBus.syncPublisher(BatchUpdateListener.TOPIC).onBatchUpdateFinished();
}
}
}
@@ -1,189 +0,0 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.components.impl.stores;
import com.intellij.openapi.components.*;
import com.intellij.openapi.components.StateStorage.SaveSession;
import com.intellij.openapi.project.impl.ProjectImpl;
import com.intellij.openapi.project.impl.ProjectManagerImpl;
import com.intellij.openapi.util.Couple;
import com.intellij.util.containers.ContainerUtil;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
public class DefaultProjectStoreImpl extends ProjectStoreImpl {
private final ProjectManagerImpl myProjectManager;
@NonNls private static final String ROOT_TAG_NAME = "defaultProject";
public DefaultProjectStoreImpl(@NotNull ProjectImpl project, @NotNull ProjectManagerImpl projectManager, @NotNull PathMacroManager pathMacroManager) {
super(project, pathMacroManager);
myProjectManager = projectManager;
}
@Nullable
Element getStateCopy() {
final Element element = myProjectManager.getDefaultProjectRootElement();
return element != null ? element.clone() : null;
}
@NotNull
@Override
protected StateStorageManager createStateStorageManager() {
final XmlElementStorage storage = new XmlElementStorage("", RoamingType.DISABLED, myPathMacroManager.createTrackingSubstitutor(),
ROOT_TAG_NAME, null) {
@Override
@Nullable
protected Element loadLocalData() {
return getStateCopy();
}
@NotNull
@Override
protected XmlElementStorageSaveSession createSaveSession(@NotNull StorageData storageData) {
return new XmlElementStorageSaveSession(storageData) {
@Override
protected void doSave(@Nullable Element element) {
// we must set empty element instead of null as indicator - ProjectManager state is ready to save
myProjectManager.setDefaultProjectRootElement(element == null ? new Element("empty") : element);
}
// we must not collapse paths here, because our solution is just a big hack
// by default, getElementToSave() returns collapsed paths -> setDefaultProjectRootElement -> project manager writeExternal -> save -> compare old and new - diff because old has expanded, but new collapsed
// -> needless save
@Override
protected boolean isCollapsePathsOnSave() {
return false;
}
};
}
@Override
@NotNull
protected StorageData createStorageData() {
return new BaseStorageData(ROOT_TAG_NAME);
}
};
//noinspection deprecation
return new StateStorageManager() {
@Override
public void addMacro(@NotNull String macro, @NotNull String expansion) {
throw new UnsupportedOperationException("Method addMacro not implemented in " + getClass());
}
@Override
@Nullable
public TrackingPathMacroSubstitutor getMacroSubstitutor() {
return null;
}
@Override
@Nullable
public StateStorage getStateStorage(@NotNull Storage storageSpec) {
return storage;
}
@Nullable
@Override
public StateStorage getStateStorage(@NotNull String fileSpec, @NotNull RoamingType roamingType) {
return storage;
}
@NotNull
@Override
public Couple<Collection<FileBasedStorage>> getCachedFileStateStorages(@NotNull Collection<String> changed, @NotNull Collection<String> deleted) {
return new Couple<Collection<FileBasedStorage>>(Collections.<FileBasedStorage>emptyList(), Collections.<FileBasedStorage>emptyList());
}
@Override
public void clearStateStorage(@NotNull String file) {
}
@Nullable
@Override
public ExternalizationSession startExternalization() {
StateStorage.ExternalizationSession externalizationSession = storage.startExternalization();
return externalizationSession == null ? null : new MyExternalizationSession(externalizationSession);
}
@NotNull
@Override
public String expandMacros(@NotNull String file) {
throw new UnsupportedOperationException("Method expandMacros not implemented in " + getClass());
}
@NotNull
@Override
public String collapseMacros(@NotNull String path) {
throw new UnsupportedOperationException("Method collapseMacros not implemented in " + getClass());
}
@Override
@Nullable
public StateStorage getOldStorage(@NotNull Object component, @NotNull String componentName, @NotNull StateStorageOperation operation) {
return storage;
}
@Override
public void setStreamProvider(@Nullable StreamProvider streamProvider) {
throw new UnsupportedOperationException("Method setStreamProvider not implemented in " + getClass());
}
@Nullable
@Override
public StreamProvider getStreamProvider() {
throw new UnsupportedOperationException("Method getStreamProviders not implemented in " + getClass());
}
@NotNull
@Override
public Collection<String> getStorageFileNames() {
throw new UnsupportedOperationException("Method getStorageFileNames not implemented in " + getClass());
}
};
}
private static class MyExternalizationSession implements StateStorageManager.ExternalizationSession {
@NotNull final StateStorage.ExternalizationSession externalizationSession;
public MyExternalizationSession(@NotNull StateStorage.ExternalizationSession externalizationSession) {
this.externalizationSession = externalizationSession;
}
@Override
public void setState(@NotNull Storage[] storageSpecs, @NotNull Object component, @NotNull String componentName, @NotNull Object state) {
externalizationSession.setState(component, componentName, state, null);
}
@Override
public void setStateInOldStorage(@NotNull Object component, @NotNull String componentName, @NotNull Object state) {
externalizationSession.setState(component, componentName, state, null);
}
@NotNull
@Override
public List<SaveSession> createSaveSessions() {
return ContainerUtil.createMaybeSingletonList(externalizationSession.createSaveSession());
}
}
}
@@ -1,121 +0,0 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.components.impl.stores;
import com.intellij.openapi.components.PathMacroSubstitutor;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.OptionManager;
import com.intellij.openapi.util.text.StringUtil;
import org.jdom.Attribute;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Set;
import java.util.TreeMap;
final class ModuleFileData extends BaseFileConfigurableStoreImpl.BaseStorageData implements OptionManager {
private TreeMap<String, String> options;
private final Module myModule;
private boolean dirty = true;
public ModuleFileData(@NotNull String rootElementName, @NotNull Module module) {
super(rootElementName);
myModule = module;
options = new TreeMap<String, String>();
}
@Override
public boolean isDirty() {
return dirty;
}
private ModuleFileData(@NotNull ModuleFileData storageData) {
super(storageData);
myModule = storageData.myModule;
dirty = storageData.dirty;
options = new TreeMap<String, String>(storageData.options);
}
@Override
public void load(@NotNull Element rootElement, @Nullable PathMacroSubstitutor pathMacroSubstitutor, boolean intern) {
super.load(rootElement, pathMacroSubstitutor, intern);
for (Attribute attribute : rootElement.getAttributes()) {
String name = attribute.getName();
if (!name.equals(BaseFileConfigurableStoreImpl.VERSION_OPTION) && !StringUtil.isEmpty(name)) {
options.put(name, attribute.getValue());
}
}
dirty = false;
}
@Override
protected void writeOptions(@NotNull Element root, @NotNull String versionString) {
if (!options.isEmpty()) {
for (String key : options.keySet()) {
String value = options.get(key);
if (value != null) {
root.setAttribute(key, value);
}
}
}
// need be last for compat reasons
super.writeOptions(root, versionString);
dirty = false;
}
@Override
public StorageData clone() {
return new ModuleFileData(this);
}
@Nullable
@Override
public Set<String> getChangedComponentNames(@NotNull StorageData newStorageData, @Nullable PathMacroSubstitutor substitutor) {
final ModuleFileData data = (ModuleFileData)newStorageData;
if (!options.equals(data.options)) {
return null;
}
return super.getChangedComponentNames(newStorageData, substitutor);
}
@Override
public void setOption(@NotNull String key, @NotNull String value) {
if (!value.equals(options.put(key, value))) {
dirty = true;
}
}
@Override
public void clearOption(@NotNull String key) {
if (options.remove(key) != null) {
dirty = true;
}
}
@Override
@Nullable
public String getOptionValue(@NotNull String key) {
return options.get(key);
}
}
@@ -1,73 +0,0 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.components.impl.stores;
import com.intellij.openapi.components.*;
import com.intellij.openapi.module.Module;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
public class ModuleStateStorageManager extends StateStorageManagerImpl {
@NonNls private static final String ROOT_TAG_NAME = "module";
private final Module myModule;
public ModuleStateStorageManager(@NotNull TrackingPathMacroSubstitutor pathMacroManager, @NotNull Module module) {
super(pathMacroManager, ROOT_TAG_NAME, module, module.getPicoContainer());
myModule = module;
}
@NotNull
@Override
protected StorageData createStorageData(@NotNull String fileSpec, @NotNull String filePath) {
return new ModuleFileData(ROOT_TAG_NAME, myModule);
}
@NotNull
@Override
public ExternalizationSession startExternalization() {
return new StateStorageManagerExternalizationSession() {
@NotNull
@Override
public List<StateStorage.SaveSession> createSaveSessions() {
StateStorageManagerImpl storageManager = (StateStorageManagerImpl)ComponentsPackage.getStateStore(myModule).getStateStorageManager();
FileBasedStorage storage = ContainerUtil.getFirstItem(storageManager.getCachedFileStorages(Collections.singletonList(StoragePathMacros.MODULE_FILE)));
if (storage != null && storage.getStorageData().isDirty()) {
// force XmlElementStorageSaveSession creation
getExternalizationSession(storage);
}
return super.createSaveSessions();
}
};
}
@Nullable
@Override
protected String getOldStorageSpec(@NotNull Object component, @NotNull String componentName, @NotNull StateStorageOperation operation) {
return StoragePathMacros.MODULE_FILE;
}
@NotNull
@Override
protected StateStorage.Listener createStorageTopicListener() {
return myModule.getProject().getMessageBus().syncPublisher(StateStorage.PROJECT_STORAGE_TOPIC);
}
}
@@ -1,55 +0,0 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.components.impl.stores;
import com.intellij.openapi.components.PathMacroManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ex.ProjectEx;
import com.intellij.util.messages.MessageBus;
import org.jetbrains.annotations.NotNull;
final class ModuleStoreImpl extends BaseFileConfigurableStoreImpl {
private final Module myModule;
public ModuleStoreImpl(@NotNull Module module, @NotNull PathMacroManager pathMacroManager) {
super(pathMacroManager);
myModule = module;
}
@Override
protected Project getProject() {
return myModule.getProject();
}
@Override
protected boolean optimizeTestLoading() {
return ((ProjectEx)myModule.getProject()).isOptimiseTestLoadSpeed();
}
@NotNull
@Override
protected MessageBus getMessageBus() {
return myModule.getMessageBus();
}
@NotNull
@Override
protected StateStorageManager createStateStorageManager() {
return new ModuleStateStorageManager(myPathMacroManager.createTrackingSubstitutor(), myModule);
}
}
@@ -1,31 +0,0 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.components.impl.stores;
import com.intellij.openapi.project.impl.ProjectStoreClassProvider;
import org.jetbrains.annotations.NotNull;
/**
* @author yole
*/
class PlatformLangProjectStoreClassProvider implements ProjectStoreClassProvider {
@NotNull
@Override
public Class<? extends IComponentStore> getProjectStoreClass(final boolean isDefaultProject) {
return isDefaultProject ? DefaultProjectStoreImpl.class : ProjectWithModulesStoreImpl.class;
}
}
@@ -1,68 +0,0 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.components.impl.stores;
import com.intellij.openapi.components.*;
import com.intellij.openapi.project.impl.ProjectImpl;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class ProjectStateStorageManager extends StateStorageManagerImpl {
protected final ProjectImpl myProject;
@NonNls protected static final String ROOT_TAG_NAME = "project";
public ProjectStateStorageManager(@NotNull TrackingPathMacroSubstitutor macroSubstitutor, @NotNull ProjectImpl project) {
super(macroSubstitutor, ROOT_TAG_NAME, project, project.getPicoContainer());
myProject = project;
}
@NotNull
@Override
protected StorageData createStorageData(@NotNull String fileSpec, @NotNull String filePath) {
if (fileSpec.equals(StoragePathMacros.PROJECT_FILE)) {
return createIprStorageData(filePath);
}
if (fileSpec.equals(StoragePathMacros.WORKSPACE_FILE)) {
return new ProjectStoreImpl.WsStorageData(ROOT_TAG_NAME, myProject);
}
return new ProjectStoreImpl.ProjectStorageData(ROOT_TAG_NAME, myProject);
}
@NotNull
protected StorageData createIprStorageData(@NotNull String filePath) {
return new ProjectStoreImpl.IprStorageData(ROOT_TAG_NAME, myProject);
}
@Nullable
@Override
protected String getOldStorageSpec(@NotNull Object component, @NotNull String componentName, @NotNull StateStorageOperation operation) {
boolean workspace = myProject.isWorkspaceComponent(component.getClass());
String fileSpec = workspace ? StoragePathMacros.WORKSPACE_FILE : StoragePathMacros.PROJECT_FILE;
StateStorage storage = getStateStorage(fileSpec, workspace ? RoamingType.DISABLED : RoamingType.PER_USER);
if (operation == StateStorageOperation.READ && storage != null && workspace && !storage.hasState(component, componentName, Element.class, false)) {
fileSpec = StoragePathMacros.PROJECT_FILE;
}
return fileSpec;
}
@NotNull
@Override
protected StateStorage.Listener createStorageTopicListener() {
return myProject.getMessageBus().syncPublisher(StateStorage.PROJECT_STORAGE_TOPIC);
}
}
@@ -1,661 +0,0 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.components.impl.stores;
import com.intellij.CommonBundle;
import com.intellij.ide.highlighter.ProjectFileType;
import com.intellij.ide.highlighter.WorkspaceFileType;
import com.intellij.notification.Notifications;
import com.intellij.notification.NotificationsManager;
import com.intellij.openapi.application.*;
import com.intellij.openapi.components.*;
import com.intellij.openapi.components.StateStorage.SaveSession;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.help.HelpManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectBundle;
import com.intellij.openapi.project.impl.ProjectImpl;
import com.intellij.openapi.project.impl.ProjectManagerImpl;
import com.intellij.openapi.project.impl.ProjectManagerImpl.UnableToSaveProjectNotification;
import com.intellij.openapi.ui.MessageDialogBuilder;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.io.FileUtilRt;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.*;
import com.intellij.util.PathUtilRt;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.lang.CompoundRuntimeException;
import com.intellij.util.messages.MessageBus;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.*;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;
public class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProjectStore {
private static final Logger LOG = Logger.getInstance(ProjectStoreImpl.class);
private static final Storage DEFAULT_STORAGE_ANNOTATION = new MyStorage();
@NonNls private static final String OLD_PROJECT_SUFFIX = "_old.";
private static int originalVersion = -1;
protected ProjectImpl myProject;
@NotNull
private StorageScheme myScheme = StorageScheme.DEFAULT;
private String myPresentableUrl;
public ProjectStoreImpl(@NotNull ProjectImpl project, @NotNull PathMacroManager pathMacroManager) {
super(pathMacroManager);
myProject = project;
}
@SuppressWarnings("unused") //used in upsource
protected void setStorageScheme(@NotNull StorageScheme scheme) {
myScheme = scheme;
}
@Override
public boolean checkVersion() {
if (originalVersion >= 0 && originalVersion < ProjectManagerImpl.CURRENT_FORMAT_VERSION) {
final VirtualFile projectFile = getProjectFile();
LOG.assertTrue(projectFile != null);
String message = ProjectBundle.message("project.convert.old.prompt", projectFile.getName(),
ApplicationNamesInfo.getInstance().getProductName(),
projectFile.getNameWithoutExtension() + OLD_PROJECT_SUFFIX + projectFile.getExtension());
if (Messages.showYesNoDialog(message, CommonBundle.getWarningTitle(), Messages.getWarningIcon()) != Messages.YES) return false;
List<String> conversionProblems = getConversionProblemsStorage();
if (!ContainerUtil.isEmpty(conversionProblems)) {
StringBuilder buffer = new StringBuilder();
buffer.append(ProjectBundle.message("project.convert.problems.detected"));
for (String s : conversionProblems) {
buffer.append('\n');
buffer.append(s);
}
buffer.append(ProjectBundle.message("project.convert.problems.help"));
if (Messages.showOkCancelDialog(myProject, buffer.toString(), ProjectBundle.message("project.convert.problems.title"),
ProjectBundle.message("project.convert.problems.help.button"),
CommonBundle.getCloseButtonText(), Messages.getWarningIcon()) == Messages.OK) {
HelpManager.getInstance().invokeHelp("project.migrationProblems");
}
}
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
try {
VirtualFile projectDir = projectFile.getParent();
assert projectDir != null;
backup(projectDir, projectFile);
VirtualFile workspaceFile = getWorkspaceFile();
if (workspaceFile != null) {
backup(projectDir, workspaceFile);
}
}
catch (IOException e) {
LOG.error(e);
}
}
private void backup(final VirtualFile projectDir, final VirtualFile vile) throws IOException {
final String oldName = vile.getNameWithoutExtension() + OLD_PROJECT_SUFFIX + vile.getExtension();
VfsUtil.saveText(projectDir.findOrCreateChildData(this, oldName), VfsUtilCore.loadText(vile));
}
});
}
return originalVersion <= ProjectManagerImpl.CURRENT_FORMAT_VERSION ||
MessageDialogBuilder.yesNo(CommonBundle.getWarningTitle(),
ProjectBundle.message("project.load.new.version.warning", myProject.getName(), ApplicationNamesInfo.getInstance().getProductName()))
.icon(Messages.getWarningIcon())
.project(myProject).is();
}
@NotNull
@Override
public TrackingPathMacroSubstitutor[] getSubstitutors() {
return new TrackingPathMacroSubstitutor[] {getStateStorageManager().getMacroSubstitutor()};
}
@Override
protected boolean optimizeTestLoading() {
return myProject.isOptimiseTestLoadSpeed();
}
@Override
protected Project getProject() {
return myProject;
}
@Override
public void setProjectFilePath(@NotNull final String filePath) {
final StateStorageManager stateStorageManager = getStateStorageManager();
final LocalFileSystem fs = LocalFileSystem.getInstance();
final File file = new File(filePath);
if (isIprPath(file)) {
myScheme = StorageScheme.DEFAULT;
stateStorageManager.addMacro(StoragePathMacros.PROJECT_FILE, filePath);
final String workspacePath = composeWsPath(filePath);
stateStorageManager.addMacro(StoragePathMacros.WORKSPACE_FILE, workspacePath);
ApplicationManager.getApplication().invokeAndWait(new Runnable() {
@Override
public void run() {
VfsUtil.markDirtyAndRefresh(false, true, false, fs.refreshAndFindFileByPath(filePath), fs.refreshAndFindFileByPath(workspacePath));
}
}, ModalityState.defaultModalityState());
}
else {
myScheme = StorageScheme.DIRECTORY_BASED;
final File dirStore = file.isDirectory() ? new File(file, Project.DIRECTORY_STORE_FOLDER)
: new File(file.getParentFile(), Project.DIRECTORY_STORE_FOLDER);
stateStorageManager.addMacro(StoragePathMacros.PROJECT_FILE, new File(dirStore, "misc.xml").getPath());
final File ws = new File(dirStore, "workspace.xml");
stateStorageManager.addMacro(StoragePathMacros.WORKSPACE_FILE, ws.getPath());
if (!ws.exists() && !file.isDirectory()) {
useOldWsContent(filePath, ws);
}
stateStorageManager.addMacro(StoragePathMacros.PROJECT_CONFIG_DIR, dirStore.getPath());
ApplicationManager.getApplication().invokeAndWait(new Runnable() {
@Override
public void run() {
VfsUtil.markDirtyAndRefresh(false, true, true, fs.refreshAndFindFileByIoFile(dirStore));
}
}, ModalityState.defaultModalityState());
}
myPresentableUrl = null;
}
private static boolean isIprPath(final File file) {
return FileUtilRt.extensionEquals(file.getName(), ProjectFileType.DEFAULT_EXTENSION);
}
private static String composeWsPath(String filePath) {
final int lastDot = filePath.lastIndexOf('.');
final String filePathWithoutExt = lastDot > 0 ? filePath.substring(0, lastDot) : filePath;
return filePathWithoutExt + WorkspaceFileType.DOT_DEFAULT_EXTENSION;
}
private static void useOldWsContent(final String filePath, final File ws) {
final File oldWs = new File(composeWsPath(filePath));
if (oldWs.exists()) {
try {
final InputStream is = new FileInputStream(oldWs);
try {
final byte[] bytes = FileUtil.loadBytes(is, (int)oldWs.length());
final OutputStream os = new FileOutputStream(ws);
try {
os.write(bytes);
}
finally {
os.close();
}
}
finally {
is.close();
}
}
catch (IOException e) {
LOG.error(e);
}
}
}
@Override
public VirtualFile getProjectBaseDir() {
if (myProject.isDefault()) return null;
final String path = getProjectBasePath();
if (path == null) return null;
return LocalFileSystem.getInstance().findFileByPath(path);
}
@Override
public String getProjectBasePath() {
if (myProject.isDefault()) return null;
final String path = getProjectFilePath();
if (!StringUtil.isEmptyOrSpaces(path)) {
return getBasePath(new File(path));
}
//we are not yet initialized completely ("open directory", etc)
StateStorage storage = getStateStorageManager().getStateStorage(StoragePathMacros.PROJECT_FILE, RoamingType.PER_USER);
if (!(storage instanceof FileBasedStorage)) {
return null;
}
return getBasePath(((FileBasedStorage)storage).getFile());
}
private String getBasePath(@NotNull File file) {
if (myScheme == StorageScheme.DEFAULT) {
return file.getParent();
}
else {
File parentFile = file.getParentFile();
return parentFile == null ? null : parentFile.getParent();
}
}
@NotNull
@Override
public String getProjectName() {
if (myScheme == StorageScheme.DIRECTORY_BASED) {
final VirtualFile baseDir = getProjectBaseDir();
assert baseDir != null : "scheme=" + myScheme + " project file=" + getProjectFilePath();
final VirtualFile ideaDir = baseDir.findChild(Project.DIRECTORY_STORE_FOLDER);
if (ideaDir != null && ideaDir.isValid()) {
final VirtualFile nameFile = ideaDir.findChild(ProjectImpl.NAME_FILE);
if (nameFile != null && nameFile.isValid()) {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(nameFile.getInputStream(), CharsetToolkit.UTF8_CHARSET));
try {
final String name = in.readLine();
if (name != null && !name.isEmpty()) {
return name.trim();
}
}
finally {
in.close();
}
}
catch (IOException ignored) { }
}
}
return baseDir.getName().replace(":", "");
}
else {
String temp = PathUtilRt.getFileName(((FileBasedStorage)getProjectFileStorage()).getFilePath());
FileType fileType = FileTypeManager.getInstance().getFileTypeByFileName(temp);
if (fileType instanceof ProjectFileType) {
temp = temp.substring(0, temp.length() - fileType.getDefaultExtension().length() - 1);
}
final int i = temp.lastIndexOf(File.separatorChar);
if (i >= 0) {
temp = temp.substring(i + 1, temp.length() - i + 1);
}
return temp;
}
}
@NotNull
@Override
public StorageScheme getStorageScheme() {
return myScheme;
}
@Override
public String getPresentableUrl() {
if (myProject.isDefault()) {
return null;
}
if (myPresentableUrl == null) {
String url = myScheme == StorageScheme.DIRECTORY_BASED ? getProjectBasePath() : getProjectFilePath();
if (url != null) {
myPresentableUrl = FileUtil.toSystemDependentName(url);
}
}
return myPresentableUrl;
}
@Override
public VirtualFile getProjectFile() {
return myProject.isDefault() ? null : ((FileBasedStorage)getProjectFileStorage()).getVirtualFile();
}
@NotNull
@Override
public String getProjectFilePath() {
return myProject.isDefault() ? "" : ((FileBasedStorage)getProjectFileStorage()).getFilePath();
}
@NotNull
private XmlElementStorage getProjectFileStorage() {
// XmlElementStorage if default project, otherwise FileBasedStorage
XmlElementStorage storage = (XmlElementStorage)getStateStorageManager().getStateStorage(StoragePathMacros.PROJECT_FILE, RoamingType.PER_USER);
assert storage != null;
return storage;
}
@Override
public VirtualFile getWorkspaceFile() {
if (myProject.isDefault()) return null;
final FileBasedStorage storage = (FileBasedStorage)getStateStorageManager().getStateStorage(StoragePathMacros.WORKSPACE_FILE, RoamingType.DISABLED);
assert storage != null;
return storage.getVirtualFile();
}
@Nullable
@Override
public String getWorkspaceFilePath() {
if (myProject.isDefault()) return null;
final FileBasedStorage storage = (FileBasedStorage)getStateStorageManager().getStateStorage(StoragePathMacros.WORKSPACE_FILE, RoamingType.DISABLED);
assert storage != null;
return storage.getFilePath();
}
@Override
public void loadProjectFromTemplate(@NotNull ProjectImpl defaultProject) {
defaultProject.save();
Element element = ((DefaultProjectStoreImpl)defaultProject.getStateStore()).getStateCopy();
if (element != null) {
getProjectFileStorage().setDefaultState(element);
}
}
@NotNull
@Override
protected StateStorageManager createStateStorageManager() {
return new ProjectStateStorageManager(myPathMacroManager.createTrackingSubstitutor(), myProject);
}
static class ProjectStorageData extends BaseStorageData {
protected final Project myProject;
ProjectStorageData(final String rootElementName, Project project) {
super(rootElementName);
myProject = project;
}
protected ProjectStorageData(ProjectStorageData storageData) {
super(storageData);
myProject = storageData.myProject;
}
@Override
public StorageData clone() {
return new ProjectStorageData(this);
}
}
static class WsStorageData extends ProjectStorageData {
WsStorageData(final String rootElementName, final Project project) {
super(rootElementName, project);
}
private WsStorageData(final WsStorageData storageData) {
super(storageData);
}
@Override
public StorageData clone() {
return new WsStorageData(this);
}
}
static class IprStorageData extends ProjectStorageData {
IprStorageData(final String rootElementName, Project project) {
super(rootElementName, project);
}
IprStorageData(final IprStorageData storageData) {
super(storageData);
}
@Override
public void load(@NotNull Element rootElement, @Nullable PathMacroSubstitutor pathMacroSubstitutor, boolean intern) {
final String v = rootElement.getAttributeValue(VERSION_OPTION);
//noinspection AssignmentToStaticFieldFromInstanceMethod
originalVersion = v != null ? Integer.parseInt(v) : 0;
if (originalVersion != ProjectManagerImpl.CURRENT_FORMAT_VERSION) {
convert(rootElement, originalVersion);
}
super.load(rootElement, pathMacroSubstitutor, intern);
}
@SuppressWarnings("UnusedParameters")
protected void convert(Element root, int originalVersion) {
}
@Override
public StorageData clone() {
return new IprStorageData(this);
}
}
@Override
protected final List<Throwable> doSave(@Nullable List<SaveSession> saveSessions, @NotNull List<Pair<SaveSession, VirtualFile>> readonlyFiles, @Nullable List<Throwable> errors) {
beforeSave(readonlyFiles);
super.doSave(saveSessions, readonlyFiles, errors);
UnableToSaveProjectNotification[] notifications =
NotificationsManager.getNotificationsManager().getNotificationsOfType(UnableToSaveProjectNotification.class, myProject);
if (readonlyFiles.isEmpty()) {
if (notifications.length > 0) {
for (UnableToSaveProjectNotification notification : notifications) {
notification.expire();
}
}
return errors;
}
if (notifications.length > 0) {
throw new SaveCancelledException();
}
ReadonlyStatusHandler.OperationStatus status;
AccessToken token = ReadAction.start();
try {
status = ReadonlyStatusHandler.getInstance(myProject).ensureFilesWritable(getFilesList(readonlyFiles));
}
finally {
token.finish();
}
if (status.hasReadonlyFiles()) {
dropUnableToSaveProjectNotification(myProject, status.getReadonlyFiles());
throw new SaveCancelledException();
}
List<Pair<SaveSession, VirtualFile>> oldList = new ArrayList<Pair<SaveSession, VirtualFile>>(readonlyFiles);
readonlyFiles.clear();
for (Pair<SaveSession, VirtualFile> entry : oldList) {
errors = executeSave(entry.first, readonlyFiles, errors);
}
if (errors != null) {
CompoundRuntimeException.doThrow(errors);
}
if (!readonlyFiles.isEmpty()) {
dropUnableToSaveProjectNotification(myProject, getFilesList(readonlyFiles));
throw new SaveCancelledException();
}
return errors;
}
private static void dropUnableToSaveProjectNotification(@NotNull Project project, @NotNull VirtualFile[] readOnlyFiles) {
UnableToSaveProjectNotification[] notifications =
NotificationsManager.getNotificationsManager().getNotificationsOfType(UnableToSaveProjectNotification.class, project);
if (notifications.length == 0) {
Notifications.Bus.notify(new UnableToSaveProjectNotification(project, readOnlyFiles), project);
}
else {
notifications[0].myFiles = readOnlyFiles;
}
}
protected void beforeSave(@NotNull List<Pair<SaveSession, VirtualFile>> readonlyFiles) {
}
@NotNull
private static VirtualFile[] getFilesList(List<Pair<SaveSession, VirtualFile>> readonlyFiles) {
final VirtualFile[] files = new VirtualFile[readonlyFiles.size()];
for (int i = 0, size = readonlyFiles.size(); i < size; i++) {
files[i] = readonlyFiles.get(i).second;
}
return files;
}
private final StateStorageChooser<PersistentStateComponent<?>> myStateStorageChooser = new StateStorageChooser<PersistentStateComponent<?>>() {
@NotNull
@Override
public Storage[] selectStorages(@NotNull Storage[] storages, @NotNull PersistentStateComponent<?> component, @NotNull StateStorageOperation operation) {
if (operation == StateStorageOperation.READ) {
List<Storage> result = new SmartList<Storage>();
for (int i = storages.length - 1; i >= 0; i--) {
Storage storage = storages[i];
if (storage.scheme() == myScheme) {
result.add(storage);
}
}
for (Storage storage : storages) {
if (storage.scheme() == StorageScheme.DEFAULT && !result.contains(storage)) {
result.add(storage);
}
}
return result.toArray(new Storage[result.size()]);
}
else if (operation == StateStorageOperation.WRITE) {
List<Storage> result = new SmartList<Storage>();
for (Storage storage : storages) {
if (storage.scheme() == myScheme) {
result.add(storage);
}
}
if (!result.isEmpty()) {
return result.toArray(new Storage[result.size()]);
}
for (Storage storage : storages) {
if (storage.scheme() == StorageScheme.DEFAULT) {
result.add(storage);
}
}
return result.toArray(new Storage[result.size()]);
}
else {
return new Storage[]{};
}
}
};
@Override
protected StateStorageChooser<PersistentStateComponent<?>> getDefaultStateStorageChooser() {
return myStateStorageChooser;
}
@NotNull
@Override
protected MessageBus getMessageBus() {
return myProject.getMessageBus();
}
@NotNull
@Override
protected <T> Storage[] getComponentStorageSpecs(@NotNull PersistentStateComponent<T> component,
@NotNull State stateSpec,
@NotNull StateStorageOperation operation) {
// if we create project from default, component state written not to own storage file, but to project file,
// we don't have time to fix it properly, so, ancient hack restored.
Storage[] result = super.getComponentStorageSpecs(component, stateSpec, operation);
// don't add fake storage if project file storage already listed, otherwise data will be deleted on write (because of "deprecated")
for (Storage storage : result) {
if (storage.file().equals(StoragePathMacros.PROJECT_FILE)) {
return result;
}
}
Storage[] withProjectFileStorage = new Storage[result.length + 1];
System.arraycopy(result, 0, withProjectFileStorage, 0, result.length);
withProjectFileStorage[result.length] = DEFAULT_STORAGE_ANNOTATION;
return withProjectFileStorage;
}
@SuppressWarnings("ClassExplicitlyAnnotation")
private static class MyStorage implements Storage {
@Override
public String id() {
return "___Default___";
}
@Override
public boolean isDefault() {
return true;
}
@Override
public String file() {
return StoragePathMacros.PROJECT_FILE;
}
@Override
public StorageScheme scheme() {
return StorageScheme.DEFAULT;
}
@Override
public boolean deprecated() {
return true;
}
@Override
public RoamingType roamingType() {
return RoamingType.PER_USER;
}
@Override
public Class<? extends StateStorage> storageClass() {
return StateStorage.class;
}
@Override
public Class<StateSplitterEx> stateSplitter() {
return StateSplitterEx.class;
}
@NotNull
@Override
public Class<? extends Annotation> annotationType() {
throw new UnsupportedOperationException("Method annotationType not implemented in " + getClass());
}
}
}
@@ -1,99 +0,0 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.components.impl.stores;
import com.intellij.openapi.components.PathMacroManager;
import com.intellij.openapi.components.StateStorage;
import com.intellij.openapi.components.StateStorage.SaveSession;
import com.intellij.openapi.components.TrackingPathMacroSubstitutor;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.impl.ProjectImpl;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Set;
public class ProjectWithModulesStoreImpl extends ProjectStoreImpl {
public ProjectWithModulesStoreImpl(@NotNull ProjectImpl project, @NotNull PathMacroManager pathMacroManager) {
super(project, pathMacroManager);
}
@Override
public boolean reinitComponent(@NotNull String componentName, @NotNull Set<StateStorage> changedStorages) {
if (super.reinitComponent(componentName, changedStorages)) {
return true;
}
for (Module module : getPersistentModules()) {
// we have to reinit all modules for component because we don't know affected module
getComponentStore(module).reinitComponent(componentName, changedStorages);
}
return true;
}
@NotNull
private static IComponentStore getComponentStore(@NotNull Module module) {
return (IComponentStore)module.getPicoContainer().getComponentInstance(IComponentStore.class);
}
@NotNull
@Override
public TrackingPathMacroSubstitutor[] getSubstitutors() {
List<TrackingPathMacroSubstitutor> result = new SmartList<TrackingPathMacroSubstitutor>();
ContainerUtil.addIfNotNull(result, getStateStorageManager().getMacroSubstitutor());
for (Module module : getPersistentModules()) {
ContainerUtil.addIfNotNull(result, getComponentStore(module).getStateStorageManager().getMacroSubstitutor());
}
return result.toArray(new TrackingPathMacroSubstitutor[result.size()]);
}
@Override
public boolean isReloadPossible(@NotNull Set<String> componentNames) {
if (!super.isReloadPossible(componentNames)) {
return false;
}
for (Module module : getPersistentModules()) {
if (!getComponentStore(module).isReloadPossible(componentNames)) {
return false;
}
}
return true;
}
@NotNull
protected Module[] getPersistentModules() {
ModuleManager moduleManager = ModuleManager.getInstance(myProject);
return moduleManager == null ? Module.EMPTY_ARRAY : moduleManager.getModules();
}
@Override
protected void beforeSave(@NotNull List<Pair<SaveSession, VirtualFile>> readonlyFiles) {
super.beforeSave(readonlyFiles);
for (Module module : getPersistentModules()) {
getComponentStore(module).save(readonlyFiles);
}
}
}
@@ -1,372 +0,0 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.components.impl.stores;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.*;
import com.intellij.openapi.components.StateStorage.SaveSession;
import com.intellij.openapi.components.StateStorageChooserEx.Resolution;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Couple;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.RoamingTypeDisabled;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.PathUtilRt;
import com.intellij.util.ReflectionUtil;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import gnu.trove.THashMap;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.picocontainer.MutablePicoContainer;
import org.picocontainer.PicoContainer;
import java.io.File;
import java.util.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public abstract class StateStorageManagerImpl implements StateStorageManager, Disposable {
private static final Logger LOG = Logger.getInstance(StateStorageManagerImpl.class);
private final Map<String, String> myMacros = new LinkedHashMap<String, String>();
private final Lock myStorageLock = new ReentrantLock();
private final Map<String, StateStorage> myStorages = new THashMap<String, StateStorage>();
private final TrackingPathMacroSubstitutor myPathMacroSubstitutor;
private final String myRootTagName;
private final PicoContainer myPicoContainer;
private StreamProvider myStreamProvider;
public StateStorageManagerImpl(@NotNull TrackingPathMacroSubstitutor pathMacroSubstitutor,
@NotNull String rootTagName,
@NotNull Disposable parentDisposable,
@NotNull PicoContainer picoContainer) {
myPicoContainer = picoContainer;
myRootTagName = rootTagName;
myPathMacroSubstitutor = pathMacroSubstitutor;
Disposer.register(parentDisposable, this);
}
@Override
public TrackingPathMacroSubstitutor getMacroSubstitutor() {
return myPathMacroSubstitutor;
}
@Override
public synchronized void addMacro(@NotNull String macro, @NotNull String expansion) {
assert !macro.isEmpty();
// backward compatibility
if (macro.charAt(0) != '$') {
LOG.warn("Add macros instead of macro name: " + macro);
expansion = '$' + macro + '$';
}
myMacros.put(macro, expansion);
}
@Nullable
protected final String getMacrosValue(@NotNull String macro) {
return myMacros.get(macro);
}
@Override
@NotNull
public StateStorage getStateStorage(@NotNull Storage storageSpec) {
String key = storageSpec.storageClass().equals(StateStorage.class) ? storageSpec.file() : storageSpec.storageClass().getName();
myStorageLock.lock();
try {
StateStorage stateStorage = myStorages.get(key);
if (stateStorage == null) {
stateStorage = createStateStorage(storageSpec.storageClass(), storageSpec.file(), storageSpec.roamingType(), storageSpec.stateSplitter());
myStorages.put(key, stateStorage);
}
return stateStorage;
}
finally {
myStorageLock.unlock();
}
}
@Nullable
@Override
public StateStorage getStateStorage(@NotNull String fileSpec, @NotNull RoamingType roamingType) {
myStorageLock.lock();
try {
StateStorage stateStorage = myStorages.get(fileSpec);
if (stateStorage == null) {
stateStorage = createStateStorage(StateStorage.class, fileSpec, roamingType, StateSplitterEx.class);
myStorages.put(fileSpec, stateStorage);
}
return stateStorage;
}
finally {
myStorageLock.unlock();
}
}
@NotNull
@Override
public Couple<Collection<FileBasedStorage>> getCachedFileStateStorages(@NotNull Collection<String> changed, @NotNull Collection<String> deleted) {
myStorageLock.lock();
try {
return Couple.of(getCachedFileStorages(changed), getCachedFileStorages(deleted));
}
finally {
myStorageLock.unlock();
}
}
@NotNull
Collection<FileBasedStorage> getCachedFileStorages(@NotNull Collection<String> fileSpecs) {
if (fileSpecs.isEmpty()) {
return Collections.emptyList();
}
List<FileBasedStorage> result = null;
for (String fileSpec : fileSpecs) {
StateStorage storage = myStorages.get(fileSpec);
if (storage instanceof FileBasedStorage) {
if (result == null) {
result = new SmartList<FileBasedStorage>();
}
result.add((FileBasedStorage)storage);
}
}
return result == null ? Collections.<FileBasedStorage>emptyList() : result;
}
@NotNull
@Override
public Collection<String> getStorageFileNames() {
myStorageLock.lock();
try {
return myStorages.keySet();
}
finally {
myStorageLock.unlock();
}
}
// overridden in upsource
protected StateStorage createStateStorage(@NotNull Class<? extends StateStorage> storageClass,
@NotNull String fileSpec,
@NotNull RoamingType roamingType,
@SuppressWarnings("deprecation") @NotNull Class<? extends StateSplitter> stateSplitter) {
if (!storageClass.equals(StateStorage.class)) {
String key = UUID.randomUUID().toString();
((MutablePicoContainer)myPicoContainer).registerComponentImplementation(key, storageClass);
return (StateStorage)myPicoContainer.getComponentInstance(key);
}
String filePath = expandMacros(fileSpec);
File file = new File(filePath);
//noinspection deprecation
if (!stateSplitter.equals(StateSplitter.class) && !stateSplitter.equals(StateSplitterEx.class)) {
return new DirectoryBasedStorage(myPathMacroSubstitutor, file, ReflectionUtil.newInstance(stateSplitter), this, createStorageTopicListener());
}
if (!ApplicationManager.getApplication().isHeadlessEnvironment() && PathUtilRt.getFileName(filePath).lastIndexOf('.') < 0) {
throw new IllegalArgumentException("Extension is missing for storage file: " + filePath);
}
if (roamingType == RoamingType.PER_USER && fileSpec.equals(StoragePathMacros.WORKSPACE_FILE)) {
roamingType = RoamingType.DISABLED;
}
beforeFileBasedStorageCreate();
return new FileBasedStorage(file, fileSpec,
roamingType, getMacroSubstitutor(fileSpec), myRootTagName, StateStorageManagerImpl.this,
createStorageTopicListener(), myStreamProvider) {
@Override
@NotNull
protected StorageData createStorageData() {
return StateStorageManagerImpl.this.createStorageData(myFileSpec, getFilePath());
}
@Override
protected boolean isUseXmlProlog() {
return StateStorageManagerImpl.this.isUseXmlProlog();
}
};
}
@Override
public void clearStateStorage(@NotNull String file) {
myStorageLock.lock();
try {
myStorages.remove(file);
}
finally {
myStorageLock.unlock();
}
}
@Nullable
protected StateStorage.Listener createStorageTopicListener() {
return null;
}
protected boolean isUseXmlProlog() {
return true;
}
protected void beforeFileBasedStorageCreate() {
}
@Nullable
@Override
public final StreamProvider getStreamProvider() {
return myStreamProvider;
}
protected TrackingPathMacroSubstitutor getMacroSubstitutor(@NotNull String fileSpec) {
return myPathMacroSubstitutor;
}
@NotNull
protected abstract StorageData createStorageData(@NotNull String fileSpec, @NotNull String filePath);
private static final Pattern MACRO_PATTERN = Pattern.compile("(\\$[^\\$]*\\$)");
@Override
@NotNull
public synchronized String expandMacros(@NotNull String file) {
Matcher matcher = MACRO_PATTERN.matcher(file);
while (matcher.find()) {
String m = matcher.group(1);
if (!myMacros.containsKey(m)) {
throw new IllegalArgumentException("Unknown macro: " + m + " in storage file spec: " + file);
}
}
String expanded = file;
for (Map.Entry<String, String> entry : myMacros.entrySet()) {
expanded = StringUtil.replace(expanded, entry.getKey(), entry.getValue());
}
return expanded;
}
@NotNull
@Override
public String collapseMacros(@NotNull String path) {
String result = path;
for (Map.Entry<String, String> entry : myMacros.entrySet()) {
result = StringUtil.replace(result, entry.getValue(), entry.getKey());
}
return result;
}
@NotNull
@Override
public ExternalizationSession startExternalization() {
return new StateStorageManagerExternalizationSession();
}
protected class StateStorageManagerExternalizationSession implements ExternalizationSession {
private final Map<StateStorage, StateStorage.ExternalizationSession> mySessions = new LinkedHashMap<StateStorage, StateStorage.ExternalizationSession>();
@Override
public void setState(@NotNull Storage[] storageSpecs, @NotNull Object component, @NotNull String componentName, @NotNull Object state) {
StateStorageChooserEx stateStorageChooser = component instanceof StateStorageChooserEx ? (StateStorageChooserEx)component : null;
for (Storage storageSpec : storageSpecs) {
Resolution resolution = stateStorageChooser == null ? Resolution.DO : stateStorageChooser.getResolution(storageSpec, StateStorageOperation.WRITE);
if (resolution == Resolution.SKIP) {
continue;
}
StateStorage stateStorage = getStateStorage(storageSpec);
StateStorage.ExternalizationSession session = getExternalizationSession(stateStorage);
if (session != null) {
// empty element as null state, so, will be deleted
session.setState(component, componentName, storageSpec.deprecated() || resolution == Resolution.CLEAR ? new Element("empty") : state, storageSpec);
}
}
}
@Override
public void setStateInOldStorage(@NotNull Object component, @NotNull String componentName, @NotNull Object state) {
StateStorage stateStorage = getOldStorage(component, componentName, StateStorageOperation.WRITE);
if (stateStorage != null) {
StateStorage.ExternalizationSession session = getExternalizationSession(stateStorage);
if (session != null) {
session.setState(component, componentName, state, null);
}
}
}
@Nullable
protected final StateStorage.ExternalizationSession getExternalizationSession(@NotNull StateStorage stateStorage) {
StateStorage.ExternalizationSession session = mySessions.get(stateStorage);
if (session == null) {
session = stateStorage.startExternalization();
if (session != null) {
mySessions.put(stateStorage, session);
}
}
return session;
}
@NotNull
@Override
public List<SaveSession> createSaveSessions() {
if (mySessions.isEmpty()) {
return Collections.emptyList();
}
List<SaveSession> saveSessions = null;
Collection<StateStorage.ExternalizationSession> externalizationSessions = mySessions.values();
for (StateStorage.ExternalizationSession session : externalizationSessions) {
SaveSession saveSession = session.createSaveSession();
if (saveSession != null) {
if (saveSessions == null) {
if (externalizationSessions.size() == 1) {
return Collections.singletonList(saveSession);
}
saveSessions = new SmartList<SaveSession>();
}
saveSessions.add(saveSession);
}
}
return ContainerUtil.notNullize(saveSessions);
}
}
@Override
@Nullable
public StateStorage getOldStorage(@NotNull Object component, @NotNull String componentName, @NotNull StateStorageOperation operation) {
String oldStorageSpec = getOldStorageSpec(component, componentName, operation);
//noinspection deprecation
return oldStorageSpec == null ? null : getStateStorage(oldStorageSpec, component instanceof RoamingTypeDisabled ? RoamingType.DISABLED : RoamingType.PER_USER);
}
@Nullable
protected abstract String getOldStorageSpec(@NotNull Object component, @NotNull String componentName, @NotNull StateStorageOperation operation);
@Override
public void dispose() {
}
@Override
public void setStreamProvider(@Nullable StreamProvider streamProvider) {
myStreamProvider = streamProvider;
}
}
@@ -19,13 +19,14 @@ import com.intellij.application.options.PathMacrosImpl
import com.intellij.openapi.Disposable
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.*
import com.intellij.openapi.components.impl.ApplicationPathMacroManager
import com.intellij.openapi.components.impl.stores.*
import com.intellij.openapi.components.impl.stores.StateStorageManager
import com.intellij.openapi.components.impl.stores.StorageData
import com.intellij.openapi.components.impl.stores.StoreUtil
import com.intellij.openapi.components.impl.stores.StreamProvider
import com.intellij.openapi.util.Disposer
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.vfs.CharsetToolkit
import com.intellij.testFramework.LightPlatformTestCase
import com.intellij.util.messages.MessageBus
import com.intellij.util.xmlb.XmlSerializerUtil
import gnu.trove.THashMap
import org.hamcrest.CoreMatchers.equalTo
@@ -40,7 +41,6 @@ public class ApplicationStoreTest : LightPlatformTestCase() {
private var testAppConfig: File? = null
private var componentStore: MyComponentStore? = null
throws(Exception::class)
override fun setUp() {
super.setUp()
@@ -56,7 +56,6 @@ public class ApplicationStoreTest : LightPlatformTestCase() {
componentStore = MyComponentStore(testAppConfig!!.getAbsolutePath())
}
throws(Exception::class)
override fun tearDown() {
try {
Disposer.dispose(componentStore!!)
@@ -119,7 +118,6 @@ public class ApplicationStoreTest : LightPlatformTestCase() {
assertThat(oldFile.exists(), equalTo(false))
}
throws(IOException::class)
private fun saveConfig(fileName: String, Language("XML") data: String): File {
val file = File(testAppConfig, fileName)
FileUtil.writeToFile(file, data)
@@ -160,16 +158,12 @@ public class ApplicationStoreTest : LightPlatformTestCase() {
init {
val macroSubstitutor = ApplicationPathMacroManager().createTrackingSubstitutor()
stateStorageManager = object : StateStorageManagerImpl(macroSubstitutor, "application", this, ApplicationManager.getApplication().getPicoContainer()) {
override fun createStorageData(fileSpec: String, filePath: String): StorageData {
return StorageData("application")
}
override fun createStorageData(fileSpec: String, filePath: String) = StorageData("application")
override fun getOldStorageSpec(component: Any, componentName: String, operation: StateStorageOperation): String? {
return null
}
override fun getOldStorageSpec(component: Any, componentName: String, operation: StateStorageOperation) = null
override fun getMacroSubstitutor(fileSpec: String): TrackingPathMacroSubstitutor? {
if (fileSpec == StoragePathMacros.APP_CONFIG + "/" + PathMacrosImpl.EXT_FILE_NAME + ".xml") {
if (fileSpec == "${StoragePathMacros.APP_CONFIG}/${PathMacrosImpl.EXT_FILE_NAME}.xml") {
return null
}
return super.getMacroSubstitutor(fileSpec)
@@ -179,16 +173,12 @@ public class ApplicationStoreTest : LightPlatformTestCase() {
stateStorageManager.addMacro(StoragePathMacros.APP_CONFIG, testAppConfigPath)
}
override fun getStateStorageManager(): StateStorageManager {
return stateStorageManager
}
override fun getStateStorageManager() = stateStorageManager
override fun dispose() {
}
override fun getMessageBus(): MessageBus {
return ApplicationManager.getApplication().getMessageBus()
}
override fun getMessageBus() = ApplicationManager.getApplication().getMessageBus()
}
abstract class Foo {
@@ -208,9 +198,7 @@ public class ApplicationStoreTest : LightPlatformTestCase() {
State(name = "HttpConfigurable", storages = arrayOf(Storage(file = StoragePathMacros.APP_CONFIG + "/other.xml", deprecated = true), Storage(file = StoragePathMacros.APP_CONFIG + "/proxy.settings.xml")))
class ActualStorageLast : Foo(), PersistentStateComponent<ActualStorageLast> {
override fun getState(): ActualStorageLast? {
return this
}
override fun getState() = this
override fun loadState(state: ActualStorageLast) {
XmlSerializerUtil.copyBean(state, this)
@@ -1,83 +0,0 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.components.impl;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.*;
import com.intellij.openapi.components.impl.stores.StateStorageManagerImpl;
import com.intellij.openapi.components.impl.stores.StorageData;
import com.intellij.openapi.util.Disposer;
import com.intellij.testFramework.LightPlatformTestCase;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.assertThat;
/**
* @author mike
*/
public class StateStorageManagerImplTest extends LightPlatformTestCase {
private StateStorageManagerImpl myStateStorageManager;
@Override
public final void setUp() throws Exception {
super.setUp();
TrackingPathMacroSubstitutor substitutor = PathMacroManager.getInstance(getProject()).createTrackingSubstitutor();
myStateStorageManager = new StateStorageManagerImpl(substitutor, "foo", myTestRootDisposable, ApplicationManager.getApplication().getPicoContainer()) {
@NotNull
@Override
protected StorageData createStorageData(@NotNull String fileSpec, @NotNull String filePath) {
throw new UnsupportedOperationException("Method createStorageData not implemented in " + getClass());
}
@Nullable
@Override
protected String getOldStorageSpec(@NotNull Object component, @NotNull String componentName, @NotNull StateStorageOperation operation) {
throw new UnsupportedOperationException("Method getOldStorageSpec not implemented in " + getClass());
}
};
myStateStorageManager.addMacro("$MACRO1$", "/temp/m1");
}
@Override
public void tearDown() throws Exception {
Disposer.dispose(myStateStorageManager);
super.tearDown();
}
public void testCreateFileStateStorageMacroSubstituted() {
StateStorage data = myStateStorageManager.getStateStorage("$MACRO1$/test.xml", RoamingType.PER_USER);
assertThat(data, is(notNullValue()));
}
public void testCreateStateStorageAssertionThrownWhenUnknownMacro() {
try {
myStateStorageManager.getStateStorage("$UNKNOWN_MACRO$/test.xml", RoamingType.PER_USER);
fail("Exception expected");
}
catch (IllegalArgumentException e) {
assertEquals("Unknown macro: $UNKNOWN_MACRO$ in storage file spec: $UNKNOWN_MACRO$/test.xml", e.getMessage());
}
}
public void testCreateFileStateStorageMacroSubstitutedWhenExpansionHas$() {
myStateStorageManager.addMacro("$DOLLAR_MACRO$", "/temp/d$");
StateStorage data = myStateStorageManager.getStateStorage("$DOLLAR_MACRO$/test.xml", RoamingType.PER_USER);
assertThat(data, is(notNullValue()));
}
}
@@ -0,0 +1,86 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.components.impl
import com.intellij.configurationStore.StateStorageManagerImpl
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.PathMacroManager
import com.intellij.openapi.components.RoamingType
import com.intellij.openapi.components.StateStorage
import com.intellij.openapi.components.StateStorageOperation
import com.intellij.openapi.components.impl.stores.StorageData
import com.intellij.openapi.util.Disposer
import com.intellij.testFramework.LightPlatformTestCase
import junit.framework.TestCase
import org.hamcrest.CoreMatchers.`is`
import org.hamcrest.CoreMatchers.notNullValue
import org.junit.Assert.assertThat
/**
* @author mike
*/
public class StateStorageManagerImplTest : LightPlatformTestCase() {
private var myStateStorageManager: StateStorageManagerImpl? = null
override fun setUp() {
super.setUp()
val substitutor = PathMacroManager.getInstance(LightPlatformTestCase.getProject()).createTrackingSubstitutor()
myStateStorageManager = object : StateStorageManagerImpl(substitutor, "foo", myTestRootDisposable, ApplicationManager.getApplication().getPicoContainer()) {
override fun createStorageData(fileSpec: String, filePath: String): StorageData {
throw UnsupportedOperationException("Method createStorageData not implemented in " + javaClass)
}
override fun getOldStorageSpec(component: Any, componentName: String, operation: StateStorageOperation): String? {
throw UnsupportedOperationException("Method getOldStorageSpec not implemented in " + javaClass)
}
}
myStateStorageManager!!.addMacro("\$MACRO1$", "/temp/m1")
}
override fun tearDown() {
try {
val storageManager = myStateStorageManager
if (storageManager != null) {
Disposer.dispose(storageManager)
}
}
finally {
super.tearDown()
}
}
public fun testCreateFileStateStorageMacroSubstituted() {
val data = myStateStorageManager!!.getStateStorage("\$MACRO1$/test.xml", RoamingType.PER_USER)
assertThat<StateStorage>(data, `is`(notNullValue()))
}
public fun testCreateStateStorageAssertionThrownWhenUnknownMacro() {
try {
myStateStorageManager!!.getStateStorage("\$UNKNOWN_MACRO$/test.xml", RoamingType.PER_USER)
TestCase.fail("Exception expected")
}
catch (e: IllegalArgumentException) {
TestCase.assertEquals("Unknown macro: \$UNKNOWN_MACRO$ in storage file spec: \$UNKNOWN_MACRO$/test.xml", e.getMessage())
}
}
public fun `testCreateFileStateStorageMacroSubstitutedWhenExpansionHas$`() {
myStateStorageManager!!.addMacro("\$DOLLAR_MACRO$", "/temp/d$")
val data = myStateStorageManager!!.getStateStorage("\$DOLLAR_MACRO$/test.xml", RoamingType.PER_USER)
assertThat<StateStorage>(data, `is`(notNullValue()))
}
}
@@ -21,8 +21,11 @@ import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ContentIterator;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileVisitor;
import com.intellij.openapi.vfs.VirtualFileWithId;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.Consumer;
@@ -145,6 +148,32 @@ public abstract class FileBasedIndex implements BaseComponent {
return processAllKeys(indexId, processor, scope.getProject());
}
public static void iterateRecursively(@Nullable final VirtualFile root,
@NotNull final ContentIterator processor,
@Nullable final ProgressIndicator indicator,
@Nullable final Set<VirtualFile> visitedRoots,
@Nullable final ProjectFileIndex projectFileIndex) {
if (root == null) {
return;
}
VfsUtilCore.visitChildrenRecursively(root, new VirtualFileVisitor() {
@Override
public boolean visitFile(@NotNull VirtualFile file) {
if (visitedRoots != null && !root.equals(file) && file.isDirectory() && !visitedRoots.add(file)) {
return false; // avoid visiting files more than once, e.g. additional indexed roots intersect sometimes
}
if (projectFileIndex != null && projectFileIndex.isExcluded(file)) {
return false;
}
if (indicator != null) indicator.checkCanceled();
processor.processFile(file);
return true;
}
});
}
public interface ValueProcessor<V> {
/**
* @param value a value to process
@@ -18,18 +18,24 @@ package com.intellij.codeInsight.completion.impl;
import com.intellij.codeInsight.completion.CompletionResult;
import com.intellij.codeInsight.completion.CompletionResultSet;
import com.intellij.codeInsight.completion.PrefixMatcher;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.codeStyle.MinusculeMatcher;
import com.intellij.util.containers.FList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author peter
*/
public class BetterPrefixMatcher extends PrefixMatcher {
private final PrefixMatcher myOriginal;
@Nullable private final CamelHumpMatcher myHumpMatcher;
private final int myMinMatchingDegree;
public BetterPrefixMatcher(PrefixMatcher original, int minMatchingDegree) {
super(original.getPrefix());
myOriginal = original;
myHumpMatcher = original instanceof CamelHumpMatcher ? (CamelHumpMatcher)original : null;
myMinMatchingDegree = minMatchingDegree;
}
@@ -47,6 +53,14 @@ public class BetterPrefixMatcher extends PrefixMatcher {
@Override
public boolean prefixMatches(@NotNull String name) {
if (myHumpMatcher != null) {
FList<TextRange> fragments = myHumpMatcher.matchingFragments(name);
if (fragments == null || !MinusculeMatcher.isStartMatch(fragments)) {
return false;
}
return myHumpMatcher.matchingDegree(name, fragments) >= myMinMatchingDegree;
}
if (!myOriginal.prefixMatches(name) || !myOriginal.isStartMatch(name)) {
return false;
}
@@ -1,4 +1,3 @@
package com.intellij.codeInsight.completion.impl;
import com.intellij.codeInsight.CodeInsightSettings;
@@ -15,6 +14,7 @@ import com.intellij.psi.codeStyle.NameUtil;
import com.intellij.util.containers.FList;
import com.intellij.util.text.CharArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
/**
@@ -139,15 +139,25 @@ public class CamelHumpMatcher extends PrefixMatcher {
@Override
public int matchingDegree(String string) {
FList<TextRange> ranges = myCaseInsensitiveMatcher.matchingFragments(string);
if (ranges != null && !ranges.isEmpty()) {
int matchStart = ranges.get(0).getStartOffset();
int underscoreEnd = skipUnderscores(string);
if (matchStart > 0 && matchStart <= underscoreEnd) {
return myCaseInsensitiveMatcher.matchingDegree(string.substring(matchStart), true) - 1;
return matchingDegree(string, matchingFragments(string));
}
public FList<TextRange> matchingFragments(String string) {
return myMatcher.matchingFragments(string);
}
public int matchingDegree(String string, @Nullable FList<TextRange> fragments) {
int underscoreEnd = skipUnderscores(string);
if (underscoreEnd > 0) {
FList<TextRange> ciRanges = myCaseInsensitiveMatcher.matchingFragments(string);
if (ciRanges != null && !ciRanges.isEmpty()) {
int matchStart = ciRanges.get(0).getStartOffset();
if (matchStart > 0 && matchStart <= underscoreEnd) {
return myCaseInsensitiveMatcher.matchingDegree(string.substring(matchStart), true) - 1;
}
}
}
return myMatcher.matchingDegree(string, true);
return myMatcher.matchingDegree(string, true, fragments);
}
}
@@ -22,6 +22,7 @@ import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressIndicatorProvider;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiCompiledElement;
import com.intellij.psi.PsiElement;
@@ -31,6 +32,7 @@ import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.proximity.PsiProximityComparator;
import com.intellij.util.*;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.FList;
import com.intellij.util.indexing.FindSymbolParameters;
import com.intellij.util.indexing.IdFilter;
import org.jetbrains.annotations.NotNull;
@@ -373,7 +375,8 @@ public class DefaultChooseByNameItemProvider implements ChooseByNameItemProvider
return null; // no matches appears valid result for "bad" pattern
}
}
return matcher.matches(name) ? new MatchResult(name, matcher.matchingDegree(name), matcher.isStartMatch(name)) : null;
FList<TextRange> fragments = matcher.matchingFragments(name);
return fragments != null ? new MatchResult(name, matcher.matchingDegree(name, false, fragments), MinusculeMatcher.isStartMatch(fragments)) : null;
}
@NotNull
@@ -2652,32 +2652,6 @@ public class FileBasedIndexImpl extends FileBasedIndex {
return tasks;
}
private static void iterateRecursively(@Nullable final VirtualFile root,
@NotNull final ContentIterator processor,
@Nullable final ProgressIndicator indicator,
@Nullable final Set<VirtualFile> visitedRoots,
@Nullable final ProjectFileIndex projectFileIndex) {
if (root == null) {
return;
}
VfsUtilCore.visitChildrenRecursively(root, new VirtualFileVisitor() {
@Override
public boolean visitFile(@NotNull VirtualFile file) {
if (visitedRoots != null && !root.equals(file) && file.isDirectory() && !visitedRoots.add(file)) {
return false; // avoid visiting files more than once, e.g. additional indexed roots intersect sometimes
}
if (projectFileIndex != null && projectFileIndex.isExcluded(file)) {
return false;
}
if (indicator != null) indicator.checkCanceled();
processor.processFile(file);
return true;
}
});
}
@SuppressWarnings({"WhileLoopSpinsOnField", "SynchronizeOnThis"})
private static class StorageGuard {
private int myHolds = 0;
@@ -239,7 +239,16 @@ public class LoadingDecorator {
@Override
public Dimension getMinimumSize() {
return myContent != null ? myContent.getMinimumSize() : super.getMinimumSize();
return myContent != null && !isMinimumSizeSet()
? myContent.getMinimumSize()
: super.getMinimumSize();
}
@Override
public Dimension getPreferredSize() {
return myContent != null && !isPreferredSizeSet()
? myContent.getPreferredSize()
: super.getPreferredSize();
}
@Override
@@ -204,7 +204,6 @@ public class ExportSettingsAction extends AnAction implements DumbAware {
storage.scheme() == StorageScheme.DEFAULT &&
!StringUtil.isEmpty(storage.file()) &&
storage.file().startsWith(StoragePathMacros.APP_CONFIG)) {
File file = new File(storageManager.expandMacros(storage.file()));
File additionalExportFile = null;
if (!StringUtil.isEmpty(stateAnnotation.additionalExportFile())) {
@@ -219,6 +218,7 @@ public class ExportSettingsAction extends AnAction implements DumbAware {
}
}
File file = new File(storageManager.expandMacros(storage.file()));
boolean fileExists = !onlyExisting || file.exists();
if (fileExists || additionalExportFile != null) {
File[] files;
@@ -74,6 +74,7 @@ import java.io.IOException;
import java.net.URL;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static com.intellij.openapi.util.text.StringUtil.isEmptyOrSpaces;
@@ -326,7 +327,7 @@ public abstract class PluginManagerMain implements Disposable {
@Override
public void run() {
final List<IdeaPluginDescriptor> list = ContainerUtil.newArrayList();
final List<String> errors = ContainerUtil.newSmartList();
final Map<String, String> errors = ContainerUtil.newLinkedHashMap();
ProgressIndicator indicator = new EmptyProgressIndicator();
List<String> hosts = RepositoryHelper.getPluginHosts();
@@ -348,7 +349,7 @@ public abstract class PluginManagerMain implements Disposable {
catch (IOException e) {
LOG.info(host, e);
if (host != ApplicationInfoEx.getInstanceEx().getBuiltinPluginsUrl()) {
errors.add(String.format("'%s' for '%s'", e.getMessage(), host));
errors.put(host, String.format("'%s' for '%s'", e.getMessage(), host));
}
}
}
@@ -369,7 +370,9 @@ public abstract class PluginManagerMain implements Disposable {
}
if (!errors.isEmpty()) {
String message = IdeBundle.message("error.list.of.plugins.was.not.loaded", StringUtil.join(errors, ", "));
String message = IdeBundle.message("error.list.of.plugins.was.not.loaded",
StringUtil.join(errors.keySet(), ", "),
StringUtil.join(errors.values(), ",\n"));
String title = IdeBundle.message("title.plugins");
String ok = CommonBundle.message("button.retry"), cancel = CommonBundle.getCancelButtonText();
if (Messages.showOkCancelDialog(message, title, ok, cancel, Messages.getErrorIcon()) == Messages.OK) {
@@ -26,8 +26,6 @@ import org.jetbrains.annotations.Nullable;
* @see com.intellij.openapi.project.ex.ProjectEx#getStateStore()
*/
public interface IProjectStore extends IComponentStore {
boolean checkVersion();
void setProjectFilePath(@NotNull String filePath);
@Nullable
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 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.
@@ -32,12 +32,12 @@ import com.intellij.openapi.project.ex.ProjectManagerEx;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.projectImport.ProjectOpenProcessor;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
public interface MergeVersion {
@@ -120,12 +120,12 @@ public interface MergeVersion {
}
@Nullable
public static Runnable prepareToReportChangedProjectFiles(@NotNull final Project project, final Collection<VirtualFile> files) {
final Set<VirtualFile> vfs = new HashSet<VirtualFile>();
for (VirtualFile vf : files) {
if (vf != null && ! vf.isDirectory()) {
if (ProjectCoreUtil.isProjectOrWorkspaceFile(vf) || isProjectFile(vf)) {
vfs.add(vf);
public static Runnable prepareToReportChangedProjectFiles(@NotNull final Project project, @NotNull Collection<VirtualFile> files) {
final Set<VirtualFile> vfs = new THashSet<VirtualFile>();
for (VirtualFile file : files) {
if (file != null && !file.isDirectory()) {
if (ProjectCoreUtil.isProjectOrWorkspaceFile(file) || isProjectFile(file)) {
vfs.add(file);
}
}
}
@@ -168,8 +168,7 @@ public interface MergeVersion {
@Override
public byte[] getBytes() throws IOException {
VirtualFile file = getFile();
if (file != null) return file.contentsToByteArray();
return myDocument.getText().getBytes();
return file != null ? file.contentsToByteArray() : myDocument.getText().getBytes();
}
@Override
@@ -191,6 +191,7 @@ final class SettingsEditor extends AbstractEditor implements DataProvider {
mySettings.select(configurable);
}
};
myEditor.setPreferredSize(JBUI.size(800, 600));
myLoadingDecorator = new LoadingDecorator(myEditor, this, 10, true);
myBanner = new Banner(myEditor.getResetAction());
mySearchPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
@@ -79,8 +79,6 @@ import java.util.concurrent.atomic.AtomicInteger;
public class ProjectManagerImpl extends ProjectManagerEx implements PersistentStateComponent<Element>, ExportableApplicationComponent {
private static final Logger LOG = Logger.getInstance(ProjectManagerImpl.class);
public static final int CURRENT_FORMAT_VERSION = 4;
private static final Key<List<ProjectManagerListener>> LISTENERS_IN_PROJECT_KEY = Key.create("LISTENERS_IN_PROJECT_KEY");
private static final Key<MultiMap<StateStorage, VirtualFile>> CHANGED_FILES_KEY = Key.create("CHANGED_FILES_KEY");
@@ -427,13 +425,10 @@ public class ProjectManagerImpl extends ProjectManagerEx implements PersistentSt
}
}
final Application application = ApplicationManager.getApplication();
if (!application.isUnitTestMode() && !((ProjectEx)project).getStateStore().checkVersion()) {
if (!addToOpened(project)) {
return false;
}
if (!addToOpened(project)) return false;
fireProjectOpened(project);
DumbService.getInstance(project).queueTask(new DumbModeTask() {
@Override
@@ -1003,9 +998,7 @@ public class ProjectManagerImpl extends ProjectManagerEx implements PersistentSt
@Override
public void loadState(Element state) {
myDefaultProjectRootElement = state.getChild("defaultProject");
if (myDefaultProjectRootElement != null) {
myDefaultProjectRootElement.detach();
}
if (myDefaultProjectRootElement != null) myDefaultProjectRootElement.detach();
myDefaultProjectConfigurationChanged = false;
}
@@ -517,7 +517,7 @@ ide.postpone.action=Postpone
title.plugins=Plugins
title.plugins.changed=Plugins Changed
plugin.status.not.specified=(not specified)
error.list.of.plugins.was.not.loaded=Unable to update the list of plugins due to the following error: {0}
error.list.of.plugins.was.not.loaded=List of plugins was not loaded for following hosts: {0}\n\nDue to the following errors:\n{1}
action.download.and.install.plugin=Download and Install
action.update.plugin=Update Plugin
error.plugin.download.failed=Plugin download failed
@@ -327,7 +327,7 @@
<projectService serviceInterface="com.intellij.openapi.roots.impl.LibraryScopeCache"
serviceImplementation="com.intellij.openapi.roots.impl.LibraryScopeCache"/>
<moduleService serviceInterface="com.intellij.openapi.components.impl.stores.IComponentStore" serviceImplementation="com.intellij.openapi.components.impl.stores.ModuleStoreImpl"/>
<moduleService serviceInterface="com.intellij.openapi.components.impl.stores.IComponentStore" serviceImplementation="com.intellij.configurationStore.ModuleStoreImpl"/>
<moduleService serviceInterface="com.intellij.openapi.components.PathMacroManager" serviceImplementation="com.intellij.openapi.components.impl.ModulePathMacroManager"/>
<projectViewPane implementation="com.intellij.ide.scratch.ScratchProjectViewPane"/>
@@ -7,9 +7,9 @@
<appStarter implementation="com.intellij.help.impl.KeymapGenerator"/>
<applicationService serviceInterface="com.intellij.openapi.components.impl.stores.IComponentStore"
serviceImplementation="com.intellij.openapi.components.impl.stores.ApplicationStoreImpl"/>
serviceImplementation="com.intellij.configurationStore.ApplicationStoreImpl"/>
<applicationService serviceInterface="com.intellij.openapi.components.PathMacroManager"
serviceImplementation="com.intellij.openapi.components.impl.ApplicationPathMacroManager"/>
serviceImplementation="com.intellij.configurationStore.ApplicationPathMacroManager"/>
<applicationService serviceImplementation="com.intellij.ide.GeneralSettings"/>
<applicationService serviceInterface="com.intellij.ide.util.PropertiesComponent"
@@ -13,7 +13,7 @@
</component>
<component>
<interface-class>com.intellij.openapi.project.impl.ProjectStoreClassProvider</interface-class>
<implementation-class>com.intellij.openapi.components.impl.stores.PlatformProjectStoreClassProvider</implementation-class>
<implementation-class>com.intellij.configurationStore.PlatformProjectStoreClassProvider</implementation-class>
</component>
</application-components>
<project-components>
@@ -13,7 +13,7 @@
</component>
<component>
<interface-class>com.intellij.openapi.project.impl.ProjectStoreClassProvider</interface-class>
<implementation-class>com.intellij.openapi.components.impl.stores.PlatformLangProjectStoreClassProvider</implementation-class>
<implementation-class>com.intellij.configurationStore.PlatformLangProjectStoreClassProvider</implementation-class>
</component>
</application-components>
<project-components>
@@ -55,7 +55,7 @@ public class StorageData extends StorageDataBase {
myRootElementName = rootElementName;
}
StorageData(@NotNull StorageData storageData) {
protected StorageData(@NotNull StorageData storageData) {
myRootElementName = storageData.myRootElementName;
myStates = new StateMap(storageData.myStates);
}
@@ -36,11 +36,6 @@ import java.util.Set;
* @author peter
*/
public class MockProjectStore implements IProjectStore {
@Override
public boolean checkVersion() {
throw new UnsupportedOperationException("Method checkVersion is not yet implemented in " + getClass().getName());
}
@Override
public void setProjectFilePath(@NotNull final String filePath) {
throw new UnsupportedOperationException("Method setProjectFilePath is not yet implemented in " + getClass().getName());
@@ -1943,7 +1943,7 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig
@Override
public void assertPreferredCompletionItems(final int selected, @NotNull @NonNls final String... expected) {
final LookupImpl lookup = getLookup();
Assert.assertNotNull(lookup);
Assert.assertNotNull("No lookup is shown", lookup);
final JList list = lookup.getList();
List<String> strings = getLookupElementStrings();
@@ -162,11 +162,14 @@ public class MinusculeMatcher implements Matcher {
}
public int matchingDegree(@NotNull String name, boolean valueStartCaseMatch) {
FList<TextRange> iterable = matchingFragments(name);
if (iterable == null) return Integer.MIN_VALUE;
if (iterable.isEmpty()) return 0;
return matchingDegree(name, valueStartCaseMatch, matchingFragments(name));
}
final TextRange first = iterable.getHead();
public int matchingDegree(@NotNull String name, boolean valueStartCaseMatch, @Nullable FList<TextRange> fragments) {
if (fragments == null) return Integer.MIN_VALUE;
if (fragments.isEmpty()) return 0;
final TextRange first = fragments.getHead();
boolean startMatch = first.getStartOffset() == 0;
int matchingCase = 0;
@@ -175,7 +178,7 @@ public class MinusculeMatcher implements Matcher {
int integral = 0; // -sum of matching-char-count * hump-index over all matched humps; favors longer fragments matching earlier words
int humpIndex = 1;
int nextHumpStart = 0;
for (TextRange range : iterable) {
for (TextRange range : fragments) {
for (int i = range.getStartOffset(); i < range.getEndOffset(); i++) {
boolean isHumpStart = false;
while (nextHumpStart <= i) {
@@ -198,7 +201,7 @@ public class MinusculeMatcher implements Matcher {
if (c == myPattern[p]) {
if (isUpperCase[p]) matchingCase += 50; // strongly prefer user's uppercase matching uppercase: they made an effort to press Shift
else if (i == 0 && startMatch) matchingCase += 15; // the very first letter case distinguishes classes in Java etc
else if (isHumpStart) matchingCase += 1; // if a lowercase matches lowercase hump start, that also means something
else if (isHumpStart) matchingCase += 1; // if a lowercase matches lowercase hump start, that also means something
} else if (isHumpStart) {
// disfavor hump starts where pattern letter case doesn't match name case
matchingCase -= 1;
@@ -209,25 +212,24 @@ public class MinusculeMatcher implements Matcher {
int startIndex = first.getStartOffset();
boolean afterSeparator = StringUtil.indexOfAny(name, myHardSeparators, 0, startIndex) >= 0;
boolean wordStart = startIndex == 0 || isWordStart(name, startIndex) && !isWordStart(name, startIndex - 1);
boolean finalMatch = iterable.get(iterable.size() - 1).getEndOffset() == name.length();
boolean finalMatch = fragments.get(fragments.size() - 1).getEndOffset() == name.length();
return (wordStart ? 1000 : 0) +
integral * 10 +
return (wordStart ? 1000 : 0) +
integral * 10 +
matchingCase * (startMatch && valueStartCaseMatch ? 10 : 1) +
(afterSeparator ? 0 : 2) +
(afterSeparator ? 0 : 2) +
(startMatch ? 1 : 0) +
(finalMatch ? 1 : 0);
}
public boolean isStartMatch(@NotNull String name) {
Iterable<TextRange> fragments = matchingFragments(name);
if (fragments != null) {
Iterator<TextRange> iterator = fragments.iterator();
if (!iterator.hasNext() || iterator.next().getStartOffset() == 0) {
return true;
}
}
return false;
FList<TextRange> fragments = matchingFragments(name);
return fragments != null && isStartMatch(fragments);
}
public static boolean isStartMatch(@NotNull Iterable<TextRange> fragments) {
Iterator<TextRange> iterator = fragments.iterator();
return !iterator.hasNext() || iterator.next().getStartOffset() == 0;
}
@Override
@@ -319,7 +319,7 @@ public class VcsUtil {
return VcsContextFactory.SERVICE.getInstance().createFilePathOn(file);
}
public static FilePath getFilePath(File file) {
public static FilePath getFilePath(@NotNull File file) {
return VcsContextFactory.SERVICE.getInstance().createFilePathOn(file);
}
@@ -331,11 +331,11 @@ public class VcsUtil {
return VcsContextFactory.SERVICE.getInstance().createFilePathOnNonLocal(path, isDirectory);
}
public static FilePath getFilePath(File file, boolean isDirectory) {
public static FilePath getFilePath(@NotNull File file, boolean isDirectory) {
return VcsContextFactory.SERVICE.getInstance().createFilePathOn(file, isDirectory);
}
public static FilePath getFilePathForDeletedFile(String path, boolean isDirectory) {
public static FilePath getFilePathForDeletedFile(@NotNull String path, boolean isDirectory) {
return VcsContextFactory.SERVICE.getInstance().createFilePathOnDeleted(new File(path), isDirectory);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2003-2014 Dave Griffith, Bas Leijdekkers
* Copyright 2003-2015 Dave Griffith, Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,34 +29,15 @@ public class EquivalenceChecker {
private EquivalenceChecker() {}
public static boolean statementsAreEquivalent(@Nullable PsiStatement statement1, @Nullable PsiStatement statement2) {
statement1 = ControlFlowUtils.stripBraces(statement1);
statement2 = ControlFlowUtils.stripBraces(statement2);
if (statement1 == null) {
return statement2 == null;
} else if (statement2 == null) {
return false;
}
if (statement1.getClass() != statement2.getClass()) {
if (statement1 instanceof PsiBlockStatement && !(statement2 instanceof PsiBlockStatement)) {
final PsiBlockStatement blockStatement = (PsiBlockStatement)statement1;
final PsiStatement[] statements = blockStatement.getCodeBlock().getStatements();
if (statements.length != 1) {
return false;
}
statement1 = statements[0];
}
else if (!(statement1 instanceof PsiBlockStatement) && statement2 instanceof PsiBlockStatement) {
final PsiBlockStatement blockStatement = (PsiBlockStatement)statement2;
final PsiStatement[] statements = blockStatement.getCodeBlock().getStatements();
if (statements.length != 1) {
return false;
}
statement2 = statements[0];
}
else {
return false;
}
if (statement1.getClass() != statement2.getClass()) {
return false;
}
}
if (statement1 instanceof PsiAssertStatement) {
return assertStatementsAreEquivalent((PsiAssertStatement)statement1, (PsiAssertStatement)statement2);
@@ -698,8 +679,12 @@ public class EquivalenceChecker {
if (classReference1 == null || classReference2 == null) {
return false;
}
final String text = classReference1.getText();
if (!text.equals(classReference2.getText())) {
final PsiElement target1 = classReference1.resolve();
if (target1 == null) {
return false;
}
final PsiElement target2 = classReference2.resolve();
if (!target1.equals(target2)) {
return false;
}
final PsiExpression[] arrayDimensions1 =
@@ -28,4 +28,23 @@ class S {
void m() {
System.out.println();
}
}
class A {
void f() {
new X();
}
class X {}
}
class BB extends A {
void f() {
new X();
}
class X {}
}
class CC extends A {
void <warning descr="Method 'f()' is identical to its super method">f</warning>() {
new X();
}
}
+1 -1
View File
@@ -15,11 +15,11 @@
*/
package org.jetbrains.settingsRepository
import com.intellij.configurationStore.ComponentStoreImpl
import com.intellij.configurationStore.SchemeManagerFactoryBase
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.WriteAction
import com.intellij.openapi.application.impl.ApplicationImpl
import com.intellij.openapi.components.impl.stores.ComponentStoreImpl
import com.intellij.openapi.components.impl.stores.FileBasedStorage
import com.intellij.openapi.components.impl.stores.IComponentStore
import com.intellij.openapi.components.impl.stores.StoreUtil
@@ -16,7 +16,7 @@
</component>
<component>
<interface-class>com.intellij.openapi.project.impl.ProjectStoreClassProvider</interface-class>
<implementation-class>com.intellij.openapi.components.impl.stores.PlatformLangProjectStoreClassProvider</implementation-class>
<implementation-class>com.intellij.configurationStore.PlatformLangProjectStoreClassProvider</implementation-class>
</component>
</application-components>
<project-components>
@@ -15,12 +15,15 @@
*/
package com.intellij.codeInsight.editorActions;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
/**
* @author Dennis.Ushakov
*/
public class EscapeEntitiesActionTest extends LightCodeInsightFixtureTestCase {
private static final String NDASH = new String(new byte[]{-30, -128, -109}, CharsetToolkit.UTF8_CHARSET);
public void testSimpleHtml() {
doTest("<<<", "html", "&lt;&lt;&lt;");
}
@@ -30,11 +33,11 @@ public class EscapeEntitiesActionTest extends LightCodeInsightFixtureTestCase {
}
public void testWide() {
doTest("\u2013", "html", "&ndash;");
doTest(NDASH, "html", "&ndash;");
}
public void testAttributeValue() {
doTest("<a alt='\u2013'></a>", "html", "<a alt='&ndash;'></a>");
doTest("<a alt='" + NDASH + "'></a>", "html", "<a alt='&ndash;'></a>");
}
public void testTag() {