From 8de507aa70eabd8cd49acb5e2e11deafa478bbb3 Mon Sep 17 00:00:00 2001 From: nik Date: Tue, 2 May 2017 20:05:48 +0300 Subject: [PATCH] project model: distinguish artifacts imported from external models This information can be used to show a warning if user tries to manually change an artifact imported from an external model in the Project Structure dialog (IDEA-171948). This information won't be saved in artifact configuration files until we implement functionality to store such artifacts separately (and enable 'store.imported.project.elements.separately' registry key), because otherwise it would lead to massive changes in files under .idea/artifacts. --- .../impl/artifacts/ArtifactImpl.java | 28 +++++++++++++------ .../impl/artifacts/ArtifactManagerImpl.java | 28 +++++++++++++++---- .../impl/artifacts/ArtifactModelImpl.java | 10 ++++++- .../impl/artifacts/InvalidArtifact.java | 6 ++-- .../packaging/artifacts/Artifact.java | 3 +- .../artifacts/ModifiableArtifactModel.java | 5 ++++ .../serialization/artifact/ArtifactState.java | 10 +++++++ 7 files changed, 72 insertions(+), 18 deletions(-) diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/ArtifactImpl.java b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/ArtifactImpl.java index 3b14386067f4..b5635bf76df5 100644 --- a/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/ArtifactImpl.java +++ b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/ArtifactImpl.java @@ -15,6 +15,7 @@ */ package com.intellij.packaging.impl.artifacts; +import com.intellij.openapi.roots.ProjectModelExternalSource; import com.intellij.openapi.util.UserDataHolderBase; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.LocalFileSystem; @@ -23,8 +24,8 @@ import com.intellij.packaging.artifacts.*; import com.intellij.packaging.elements.CompositePackagingElement; import com.intellij.packaging.impl.elements.ArchivePackagingElement; import com.intellij.util.EventDispatcher; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Collection; @@ -43,20 +44,24 @@ public class ArtifactImpl extends UserDataHolderBase implements ModifiableArtifa private final EventDispatcher myDispatcher; private ArtifactType myArtifactType; private Map> myProperties; + private final ProjectModelExternalSource myExternalSource; - public ArtifactImpl(@NotNull String name, @NotNull ArtifactType artifactType, boolean buildOnMake, @NotNull CompositePackagingElement rootElement, - String outputPath) { - this(name, artifactType, buildOnMake, rootElement, outputPath, null); + public ArtifactImpl(@NotNull String name, @NotNull ArtifactType artifactType, boolean buildOnMake, + @NotNull CompositePackagingElement rootElement, String outputPath, + @Nullable ProjectModelExternalSource externalSource) { + this(name, artifactType, buildOnMake, rootElement, outputPath, externalSource, null); } - public ArtifactImpl(@NotNull String name, @NotNull ArtifactType artifactType, boolean buildOnMake, @NotNull CompositePackagingElement rootElement, - String outputPath, - EventDispatcher dispatcher) { + + public ArtifactImpl(@NotNull String name, @NotNull ArtifactType artifactType, boolean buildOnMake, + @NotNull CompositePackagingElement rootElement, String outputPath, + @Nullable ProjectModelExternalSource externalSource, EventDispatcher dispatcher) { myName = name; myArtifactType = artifactType; myBuildOnMake = buildOnMake; myRootElement = rootElement; myOutputPath = outputPath; myDispatcher = dispatcher; + myExternalSource = externalSource; myProperties = new HashMap<>(); resetProperties(); } @@ -96,8 +101,15 @@ public class ArtifactImpl extends UserDataHolderBase implements ModifiableArtifa return Collections.unmodifiableCollection(myProperties.keySet()); } + @Nullable + @Override + public ProjectModelExternalSource getExternalSource() { + return myExternalSource; + } + public ArtifactImpl createCopy(EventDispatcher dispatcher) { - final ArtifactImpl artifact = new ArtifactImpl(myName, myArtifactType, myBuildOnMake, myRootElement, myOutputPath, dispatcher); + final ArtifactImpl artifact = new ArtifactImpl(myName, myArtifactType, myBuildOnMake, myRootElement, myOutputPath, myExternalSource, + dispatcher); for (Map.Entry> entry : myProperties.entrySet()) { final ArtifactProperties newProperties = artifact.myProperties.get(entry.getKey()); //noinspection unchecked diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/ArtifactManagerImpl.java b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/ArtifactManagerImpl.java index 38c548a0ea28..ab10a1c5b092 100644 --- a/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/ArtifactManagerImpl.java +++ b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/ArtifactManagerImpl.java @@ -25,11 +25,14 @@ import com.intellij.openapi.components.Storage; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.ProjectLoadingErrorsNotifier; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ExternalProjectSystemRegistry; +import com.intellij.openapi.roots.ProjectModelExternalSource; import com.intellij.openapi.roots.ex.ProjectRootManagerEx; import com.intellij.openapi.updateSettings.impl.pluginsAdvertisement.UnknownFeaturesCollector; import com.intellij.openapi.util.ModificationTracker; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.SimpleModificationTracker; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.packaging.artifacts.*; @@ -122,6 +125,12 @@ public class ArtifactManagerImpl extends ArtifactManager implements ProjectCompo artifactState.setOutputPath(artifact.getOutputPath()); artifactState.setRootElement(serializePackagingElement(artifact.getRootElement())); artifactState.setArtifactType(artifact.getArtifactType().getId()); + ProjectModelExternalSource externalSource = artifact.getExternalSource(); + if (externalSource != null && Registry.is("store.imported.project.elements.separately")) { + //we can add this attribute only if the artifact configuration will be stored separately, otherwise we will get modified files in .idea/artifacts. + artifactState.setExternalSystemId(externalSource.getId()); + } + for (ArtifactPropertiesProvider provider : artifact.getPropertiesProviders()) { final ArtifactPropertiesState propertiesState = serializeProperties(provider, artifact.getProperties(provider)); if (propertiesState != null) { @@ -210,8 +219,9 @@ public class ArtifactManagerImpl extends ArtifactManager implements ProjectCompo private ArtifactImpl loadArtifact(ArtifactState state) { ArtifactType type = ArtifactType.findById(state.getArtifactType()); + ProjectModelExternalSource externalSource = findExternalSource(state.getExternalSystemId()); if (type == null) { - return createInvalidArtifact(state, "Unknown artifact type: " + state.getArtifactType()); + return createInvalidArtifact(state, externalSource, "Unknown artifact type: " + state.getArtifactType()); } final Element element = state.getRootElement(); @@ -222,14 +232,15 @@ public class ArtifactManagerImpl extends ArtifactManager implements ProjectCompo rootElement = (CompositePackagingElement)deserializeElement(element); } catch (UnknownPackagingElementTypeException e) { - return createInvalidArtifact(state, "Unknown element: " + e.getTypeId()); + return createInvalidArtifact(state, externalSource, "Unknown element: " + e.getTypeId()); } } else { rootElement = type.createRootElement(artifactName); } - final ArtifactImpl artifact = new ArtifactImpl(artifactName, type, state.isBuildOnMake(), rootElement, state.getOutputPath()); + final ArtifactImpl artifact = new ArtifactImpl(artifactName, type, state.isBuildOnMake(), rootElement, state.getOutputPath(), + externalSource); final List propertiesList = state.getPropertiesList(); for (ArtifactPropertiesState propertiesState : propertiesList) { final ArtifactPropertiesProvider provider = ArtifactPropertiesProvider.findById(propertiesState.getId()); @@ -237,19 +248,24 @@ public class ArtifactManagerImpl extends ArtifactManager implements ProjectCompo deserializeProperties(artifact.getProperties(provider), propertiesState); } else { - return createInvalidArtifact(state, "Unknown artifact properties: " + propertiesState.getId()); + return createInvalidArtifact(state, externalSource, "Unknown artifact properties: " + propertiesState.getId()); } } return artifact; } - private InvalidArtifact createInvalidArtifact(ArtifactState state, String errorMessage) { - final InvalidArtifact artifact = new InvalidArtifact(state, errorMessage); + private InvalidArtifact createInvalidArtifact(ArtifactState state, ProjectModelExternalSource externalSource, String errorMessage) { + final InvalidArtifact artifact = new InvalidArtifact(state, errorMessage, externalSource); ProjectLoadingErrorsNotifier.getInstance(myProject).registerError(new ArtifactLoadingErrorDescription(myProject, artifact)); UnknownFeaturesCollector.getInstance(myProject).registerUnknownFeature("com.intellij.packaging.artifacts.ArtifactType", state.getArtifactType(), "Artifact"); return artifact; } + @Nullable + private static ProjectModelExternalSource findExternalSource(@Nullable String externalSourceId) { + return externalSourceId != null ? ExternalProjectSystemRegistry.getInstance().getSourceById(externalSourceId) : null; + } + private static void deserializeProperties(ArtifactProperties artifactProperties, ArtifactPropertiesState propertiesState) { final Element options = propertiesState.getOptions(); if (artifactProperties == null || options == null) { diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/ArtifactModelImpl.java b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/ArtifactModelImpl.java index e3af7f8ff3f1..5ccaf6a6a35a 100644 --- a/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/ArtifactModelImpl.java +++ b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/ArtifactModelImpl.java @@ -15,6 +15,7 @@ */ package com.intellij.packaging.impl.artifacts; +import com.intellij.openapi.roots.ProjectModelExternalSource; import com.intellij.packaging.artifacts.*; import com.intellij.packaging.elements.CompositePackagingElement; import com.intellij.util.EventDispatcher; @@ -68,9 +69,16 @@ public class ArtifactModelImpl extends ArtifactModelBase implements ModifiableAr @NotNull public ModifiableArtifact addArtifact(@NotNull String name, @NotNull ArtifactType artifactType, CompositePackagingElement rootElement) { + return addArtifact(name, artifactType, rootElement, null); + } + + @Override + @NotNull + public ModifiableArtifact addArtifact(@NotNull String name, @NotNull ArtifactType artifactType, CompositePackagingElement rootElement, + @Nullable ProjectModelExternalSource externalSource) { final String uniqueName = generateUniqueName(name); final String outputPath = ArtifactUtil.getDefaultArtifactOutputPath(uniqueName, myArtifactManager.getProject()); - final ArtifactImpl artifact = new ArtifactImpl(uniqueName, artifactType, false, rootElement, outputPath, myDispatcher); + final ArtifactImpl artifact = new ArtifactImpl(uniqueName, artifactType, false, rootElement, outputPath, externalSource, myDispatcher); myOriginalArtifacts.add(artifact); myArtifact2ModifiableCopy.put(artifact, artifact); myModifiable2Original.put(artifact, artifact); diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/InvalidArtifact.java b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/InvalidArtifact.java index c6df02ec5188..06c44fe6bc34 100644 --- a/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/InvalidArtifact.java +++ b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/InvalidArtifact.java @@ -15,6 +15,7 @@ */ package com.intellij.packaging.impl.artifacts; +import com.intellij.openapi.roots.ProjectModelExternalSource; import com.intellij.packaging.elements.PackagingElementFactory; import org.jetbrains.jps.model.serialization.artifact.ArtifactState; @@ -25,8 +26,9 @@ public class InvalidArtifact extends ArtifactImpl { private ArtifactState myState; private final String myErrorMessage; - public InvalidArtifact(ArtifactState state, String errorMessage) { - super(state.getName(), InvalidArtifactType.getInstance(), false, PackagingElementFactory.getInstance().createArtifactRootElement(), ""); + public InvalidArtifact(ArtifactState state, String errorMessage, ProjectModelExternalSource externalSource) { + super(state.getName(), InvalidArtifactType.getInstance(), false, PackagingElementFactory.getInstance().createArtifactRootElement(), "", + externalSource); myState = state; myErrorMessage = errorMessage; } diff --git a/java/compiler/openapi/src/com/intellij/packaging/artifacts/Artifact.java b/java/compiler/openapi/src/com/intellij/packaging/artifacts/Artifact.java index 8155cf05af6e..318d6a5e7d6e 100644 --- a/java/compiler/openapi/src/com/intellij/packaging/artifacts/Artifact.java +++ b/java/compiler/openapi/src/com/intellij/packaging/artifacts/Artifact.java @@ -15,6 +15,7 @@ */ package com.intellij.packaging.artifacts; +import com.intellij.openapi.roots.ProjectModelElement; import com.intellij.openapi.util.UserDataHolder; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.packaging.elements.CompositePackagingElement; @@ -26,7 +27,7 @@ import java.util.Collection; /** * @author nik */ -public interface Artifact extends UserDataHolder { +public interface Artifact extends UserDataHolder, ProjectModelElement { @NotNull ArtifactType getArtifactType(); diff --git a/java/compiler/openapi/src/com/intellij/packaging/artifacts/ModifiableArtifactModel.java b/java/compiler/openapi/src/com/intellij/packaging/artifacts/ModifiableArtifactModel.java index 5e6172f8e6c2..ef0f2d61b419 100644 --- a/java/compiler/openapi/src/com/intellij/packaging/artifacts/ModifiableArtifactModel.java +++ b/java/compiler/openapi/src/com/intellij/packaging/artifacts/ModifiableArtifactModel.java @@ -15,6 +15,7 @@ */ package com.intellij.packaging.artifacts; +import com.intellij.openapi.roots.ProjectModelExternalSource; import com.intellij.packaging.elements.CompositePackagingElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -30,6 +31,10 @@ public interface ModifiableArtifactModel extends ArtifactModel { @NotNull ModifiableArtifact addArtifact(final @NotNull String name, @NotNull ArtifactType artifactType, CompositePackagingElement rootElement); + @NotNull + ModifiableArtifact addArtifact(@NotNull String name, @NotNull ArtifactType artifactType, CompositePackagingElement rootElement, + @Nullable ProjectModelExternalSource externalSource); + void removeArtifact(@NotNull Artifact artifact); @NotNull diff --git a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/artifact/ArtifactState.java b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/artifact/ArtifactState.java index 060d281d3331..4ec515c71f3c 100644 --- a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/artifact/ArtifactState.java +++ b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/artifact/ArtifactState.java @@ -37,6 +37,7 @@ public class ArtifactState { private boolean myBuildOnMake; private Element myRootElement; private List myPropertiesList = new ArrayList<>(); + private String myExternalSystemId; @Attribute(NAME_ATTRIBUTE) public String getName() { @@ -53,6 +54,11 @@ public class ArtifactState { return myBuildOnMake; } + @Attribute("external-system-id") + public String getExternalSystemId() { + return myExternalSystemId; + } + @Tag("output-path") public String getOutputPath() { return myOutputPath; @@ -89,6 +95,10 @@ public class ArtifactState { myBuildOnMake = buildOnMake; } + public void setExternalSystemId(String externalSystemId) { + myExternalSystemId = externalSystemId; + } + public void setRootElement(Element rootElement) { myRootElement = rootElement; }