mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
project model: store configurations of facets imported from external sources in a separate component
This is needed to store such configurations in a separate file (IDEA-171877) while saving configurations of regular manually created facets in *.iml file.
This commit is contained in:
+10
@@ -32,6 +32,7 @@ import java.util.ArrayList;
|
||||
public class FacetState {
|
||||
private String myFacetType;
|
||||
private String myName;
|
||||
private String myExternalSystemId;
|
||||
private Element myConfiguration;
|
||||
private List<FacetState> mySubFacets = new ArrayList<>();
|
||||
|
||||
@@ -50,6 +51,11 @@ public class FacetState {
|
||||
return myConfiguration;
|
||||
}
|
||||
|
||||
@Attribute("external-system-id")
|
||||
public String getExternalSystemId() {
|
||||
return myExternalSystemId;
|
||||
}
|
||||
|
||||
@Property(surroundWithTag = false)
|
||||
@AbstractCollection(surroundWithTag = false)
|
||||
public List<FacetState> getSubFacets() {
|
||||
@@ -71,4 +77,8 @@ public class FacetState {
|
||||
public void setFacetType(final String type) {
|
||||
myFacetType = type;
|
||||
}
|
||||
|
||||
public void setExternalSystemId(String externalSystemId) {
|
||||
myExternalSystemId = externalSystemId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.facet;
|
||||
|
||||
import com.intellij.openapi.components.PersistentStateComponent;
|
||||
import com.intellij.openapi.components.State;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleServiceManager;
|
||||
import com.intellij.openapi.roots.ProjectModelElement;
|
||||
import com.intellij.openapi.roots.ProjectModelExternalSource;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.xmlb.XmlSerializerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.model.serialization.facet.FacetManagerState;
|
||||
|
||||
/**
|
||||
* @author nik
|
||||
*/
|
||||
@State(name = "FacetsFromExternalSources")
|
||||
public class FacetFromExternalSourcesStorage implements PersistentStateComponent<FacetManagerState>, ProjectModelElement {
|
||||
private FacetManagerState myState = new FacetManagerState();
|
||||
private Module myModule;
|
||||
|
||||
public static FacetFromExternalSourcesStorage getInstance(Module module) {
|
||||
return ModuleServiceManager.getService(module, FacetFromExternalSourcesStorage.class);
|
||||
}
|
||||
|
||||
public FacetFromExternalSourcesStorage(@NotNull Module module) {
|
||||
myModule = module;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public FacetManagerState getState() {
|
||||
myState = ((FacetManagerImpl)FacetManager.getInstance(myModule)).saveState(FacetManagerImpl.getImportedFacetPredicate());
|
||||
return myState;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
FacetManagerState getLoadedState() {
|
||||
return myState;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ProjectModelExternalSource getExternalSource() {
|
||||
//If different facets came from different external sources it actually doesn't matter which source is returned from this method,
|
||||
// it's enough to return any non-null value to serialize this component into a separate file.
|
||||
return ContainerUtil.getFirstItem(((FacetManagerImpl)FacetManager.getInstance(myModule)).getExternalSources());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadState(FacetManagerState state) {
|
||||
XmlSerializerUtil.copyBean(state, myState);
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.intellij.facet;
|
||||
|
||||
import com.google.common.base.Predicates;
|
||||
import com.intellij.facet.impl.FacetLoadingErrorDescription;
|
||||
import com.intellij.facet.impl.FacetModelBase;
|
||||
import com.intellij.facet.impl.FacetModelImpl;
|
||||
@@ -33,10 +34,13 @@ import com.intellij.openapi.module.ModuleComponent;
|
||||
import com.intellij.openapi.module.ModuleType;
|
||||
import com.intellij.openapi.module.ProjectLoadingErrorsNotifier;
|
||||
import com.intellij.openapi.project.ProjectBundle;
|
||||
import com.intellij.openapi.roots.ExternalProjectSystemRegistry;
|
||||
import com.intellij.openapi.roots.ProjectModelExternalSource;
|
||||
import com.intellij.openapi.updateSettings.impl.pluginsAdvertisement.UnknownFeaturesCollector;
|
||||
import com.intellij.openapi.util.*;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.messages.MessageBus;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
@@ -46,6 +50,7 @@ import org.jetbrains.jps.model.serialization.facet.FacetManagerState;
|
||||
import org.jetbrains.jps.model.serialization.facet.FacetState;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* @author nik
|
||||
@@ -239,39 +244,75 @@ public class FacetManagerImpl extends FacetManager implements ModuleComponent, P
|
||||
}
|
||||
}
|
||||
|
||||
private <C extends FacetConfiguration> void addFacet(final FacetType<?, C> type, final FacetState state, final Facet underlyingFacet,
|
||||
final ModifiableFacetModel model) throws InvalidDataException {
|
||||
if (type.isOnlyOneFacetAllowed() &&
|
||||
(underlyingFacet == null && !model.getFacetsByType(type.getId()).isEmpty() ||
|
||||
underlyingFacet != null && !model.getFacetsByType(underlyingFacet, type.getId()).isEmpty())) {
|
||||
private <F extends Facet<C>, C extends FacetConfiguration> void addFacet(final FacetType<F, C> type, final FacetState state, final Facet underlyingFacet,
|
||||
final ModifiableFacetModel model) throws InvalidDataException {
|
||||
Collection<F> facetsOfThisType = underlyingFacet == null ? model.getFacetsByType(type.getId())
|
||||
: model.getFacetsByType(underlyingFacet, type.getId());
|
||||
if (type.isOnlyOneFacetAllowed() && !facetsOfThisType.isEmpty() && facetsOfThisType.stream().anyMatch(f -> !f.getName().equals(state.getName()))) {
|
||||
LOG.info("'" + state.getName() + "' facet removed from module " + myModule.getName() + ", because only one "
|
||||
+ type.getPresentableName() + " facet allowed");
|
||||
return;
|
||||
}
|
||||
final C configuration = type.createDefaultConfiguration();
|
||||
final Element config = state.getConfiguration();
|
||||
FacetUtil.loadFacetConfiguration(configuration, config);
|
||||
String name = state.getName();
|
||||
final Facet facet = createFacet(type, name, configuration, underlyingFacet);
|
||||
if (facet instanceof JDOMExternalizable) {
|
||||
//todo[nik] remove
|
||||
((JDOMExternalizable)facet).readExternal(config);
|
||||
|
||||
F facet = null;
|
||||
if (!facetsOfThisType.isEmpty() && Registry.is("store.imported.project.elements.separately")) {
|
||||
facet = facetsOfThisType.stream().filter(f -> f.getName().equals(state.getName())).findFirst().orElse(null);
|
||||
if (facet != null) {
|
||||
Element newConfiguration = state.getConfiguration();
|
||||
//There may be two states of the same facet if configuration is stored in one file but configuration of its sub-facet is stored in another.
|
||||
//In that case only one of the states will have the real configuration and we'll merge them here.
|
||||
if (newConfiguration != null) {
|
||||
FacetUtil.loadFacetConfiguration(facet.getConfiguration(), newConfiguration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (facet == null) {
|
||||
final C configuration = type.createDefaultConfiguration();
|
||||
final Element config = state.getConfiguration();
|
||||
FacetUtil.loadFacetConfiguration(configuration, config);
|
||||
String name = state.getName();
|
||||
facet = createFacet(type, name, configuration, underlyingFacet);
|
||||
if (facet instanceof JDOMExternalizable) {
|
||||
//todo[nik] remove
|
||||
((JDOMExternalizable)facet).readExternal(config);
|
||||
}
|
||||
String externalSystemId = state.getExternalSystemId();
|
||||
if (externalSystemId != null) {
|
||||
facet.setExternalSource(ExternalProjectSystemRegistry.getInstance().getSourceById(externalSystemId));
|
||||
}
|
||||
model.addFacet(facet);
|
||||
}
|
||||
model.addFacet(facet);
|
||||
addFacets(state.getSubFacets(), facet, model);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadState(final FacetManagerState state) {
|
||||
ModifiableFacetModel model = new FacetModelImpl(this);
|
||||
FacetManagerState importedFacetsState = FacetFromExternalSourcesStorage.getInstance(myModule).getLoadedState();
|
||||
|
||||
addFacets(state.getFacets(), null, model);
|
||||
addFacets(ContainerUtil.concat(state.getFacets(), importedFacetsState.getFacets()), null, model);
|
||||
|
||||
commit(model, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public FacetManagerState getState() {
|
||||
return saveState(getImportedFacetPredicate().negate());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static Predicate<Facet> getImportedFacetPredicate() {
|
||||
if (Registry.is("store.imported.project.elements.separately")) {
|
||||
//we can store imported facets in a separate component only if that component will be stored separately, otherwise we will get modified *.iml files
|
||||
return facet -> facet.getExternalSource() != null;
|
||||
}
|
||||
return Predicates.alwaysFalse();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
FacetManagerState saveState(Predicate<Facet> filter) {
|
||||
FacetManagerState managerState = new FacetManagerState();
|
||||
|
||||
final Facet[] facets = getSortedFacets();
|
||||
@@ -280,17 +321,11 @@ public class FacetManagerImpl extends FacetManager implements ModuleComponent, P
|
||||
states.put(null, managerState.getFacets());
|
||||
|
||||
for (Facet facet : facets) {
|
||||
if (!filter.test(facet)) continue;
|
||||
final Facet underlyingFacet = facet.getUnderlyingFacet();
|
||||
final List<FacetState> parent = states.get(underlyingFacet);
|
||||
|
||||
FacetState facetState;
|
||||
if (facet instanceof InvalidFacet) {
|
||||
facetState = ((InvalidFacet)facet).getConfiguration().getFacetState();
|
||||
}
|
||||
else {
|
||||
facetState = new FacetState();
|
||||
facetState.setFacetType(facet.getType().getStringId());
|
||||
facetState.setName(facet.getName());
|
||||
FacetState facetState = createFacetState(facet);
|
||||
if (!(facet instanceof InvalidFacet)) {
|
||||
final Element config;
|
||||
try {
|
||||
FacetConfiguration configuration = facet.getConfiguration();
|
||||
@@ -306,12 +341,44 @@ public class FacetManagerImpl extends FacetManager implements ModuleComponent, P
|
||||
facetState.setConfiguration(config);
|
||||
}
|
||||
|
||||
parent.add(facetState);
|
||||
getOrCreateTargetFacetList(underlyingFacet, states).add(facetState);
|
||||
states.put(facet, facetState.getSubFacets());
|
||||
}
|
||||
return managerState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration of some facet may be stored in one file, but configuration of its underlying facet may be stored in another file. For such
|
||||
* sub-facets we create parent elements which don't store configuration but only name and type.
|
||||
*/
|
||||
private static List<FacetState> getOrCreateTargetFacetList(Facet underlyingFacet, Map<Facet, List<FacetState>> states) {
|
||||
List<FacetState> facetStateList = states.get(underlyingFacet);
|
||||
if (facetStateList == null) {
|
||||
FacetState state = createFacetState(underlyingFacet);
|
||||
getOrCreateTargetFacetList(underlyingFacet.getUnderlyingFacet(), states).add(state);
|
||||
facetStateList = state.getSubFacets();
|
||||
states.put(underlyingFacet, facetStateList);
|
||||
}
|
||||
return facetStateList;
|
||||
}
|
||||
|
||||
private static FacetState createFacetState(Facet facet) {
|
||||
if (facet instanceof InvalidFacet) {
|
||||
return ((InvalidFacet)facet).getConfiguration().getFacetState();
|
||||
}
|
||||
else {
|
||||
FacetState facetState = new FacetState();
|
||||
ProjectModelExternalSource externalSource = facet.getExternalSource();
|
||||
if (externalSource != null && Registry.is("store.imported.project.elements.separately")) {
|
||||
//set this attribute only if such facets will be stored separately, otherwise we will get modified *.iml files
|
||||
facetState.setExternalSystemId(externalSource.getId());
|
||||
}
|
||||
facetState.setFacetType(facet.getType().getStringId());
|
||||
facetState.setName(facet.getName());
|
||||
return facetState;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void commit(final ModifiableFacetModel model) {
|
||||
ApplicationManager.getApplication().assertWriteAccessAllowed();
|
||||
@@ -423,6 +490,10 @@ public class FacetManagerImpl extends FacetManager implements ModuleComponent, P
|
||||
facet.setExternalSource(externalSource);
|
||||
}
|
||||
|
||||
Set<ProjectModelExternalSource> getExternalSources() {
|
||||
return myModel.myExternalSources;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moduleAdded() {
|
||||
if (myModuleAdded) return;
|
||||
@@ -442,6 +513,7 @@ public class FacetManagerImpl extends FacetManager implements ModuleComponent, P
|
||||
|
||||
private static class FacetManagerModel extends FacetModelBase {
|
||||
private Facet[] myAllFacets = Facet.EMPTY_ARRAY;
|
||||
private Set<ProjectModelExternalSource> myExternalSources = new LinkedHashSet<>();
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
@@ -450,6 +522,10 @@ public class FacetManagerImpl extends FacetManager implements ModuleComponent, P
|
||||
}
|
||||
|
||||
public void setAllFacets(final Facet[] allFacets) {
|
||||
myExternalSources.clear();
|
||||
for (Facet facet : allFacets) {
|
||||
ContainerUtil.addIfNotNull(myExternalSources, facet.getExternalSource());
|
||||
}
|
||||
myAllFacets = allFacets;
|
||||
facetsChanged();
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package com.intellij.facet.impl.invalid;
|
||||
|
||||
import com.intellij.facet.FacetConfiguration;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.model.serialization.facet.FacetState;
|
||||
import com.intellij.facet.ui.FacetEditorContext;
|
||||
import com.intellij.facet.ui.FacetEditorTab;
|
||||
@@ -36,6 +37,7 @@ public class InvalidFacetConfiguration implements FacetConfiguration {
|
||||
myErrorMessage = errorMessage;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public FacetState getFacetState() {
|
||||
return myFacetState;
|
||||
}
|
||||
|
||||
@@ -254,6 +254,7 @@
|
||||
|
||||
<moduleService serviceInterface="com.intellij.facet.FacetModificationTrackingService"
|
||||
serviceImplementation="com.intellij.facet.impl.FacetModificationTrackingServiceImpl"/>
|
||||
<moduleService serviceImplementation="com.intellij.facet.FacetFromExternalSourcesStorage"/>
|
||||
|
||||
<applicationService serviceInterface="com.intellij.framework.detection.impl.FrameworkDetectorRegistry"
|
||||
serviceImplementation="com.intellij.framework.detection.impl.FrameworkDetectorRegistryImpl"/>
|
||||
|
||||
Reference in New Issue
Block a user