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.
This commit is contained in:
nik
2017-05-03 10:21:20 +03:00
parent 1dfcdcd1a8
commit 8de507aa70
7 changed files with 72 additions and 18 deletions
@@ -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<ArtifactListener> myDispatcher;
private ArtifactType myArtifactType;
private Map<ArtifactPropertiesProvider, ArtifactProperties<?>> 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<ArtifactListener> dispatcher) {
public ArtifactImpl(@NotNull String name, @NotNull ArtifactType artifactType, boolean buildOnMake,
@NotNull CompositePackagingElement<?> rootElement, String outputPath,
@Nullable ProjectModelExternalSource externalSource, EventDispatcher<ArtifactListener> 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<ArtifactListener> 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<ArtifactPropertiesProvider, ArtifactProperties<?>> entry : myProperties.entrySet()) {
final ArtifactProperties newProperties = artifact.myProperties.get(entry.getKey());
//noinspection unchecked
@@ -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<ArtifactPropertiesState> 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 <S> void deserializeProperties(ArtifactProperties<S> artifactProperties, ArtifactPropertiesState propertiesState) {
final Element options = propertiesState.getOptions();
if (artifactProperties == null || options == null) {
@@ -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);
@@ -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;
}
@@ -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();
@@ -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
@@ -37,6 +37,7 @@ public class ArtifactState {
private boolean myBuildOnMake;
private Element myRootElement;
private List<ArtifactPropertiesState> 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;
}