From 378f2e91e922ca60d19c8bbc300e7caa9392faf2 Mon Sep 17 00:00:00 2001 From: nik Date: Wed, 31 Mar 2010 12:12:51 +0400 Subject: [PATCH] IDEA-53319: IDEA 9.0.1 Very Brittle With Deployments (corrupts projects, overwrites directories, ...) --- .../impl/artifacts/ArtifactUtil.java | 36 ++++++--- .../artifacts/ArtifactValidationUtil.java | 34 +++++++++ .../artifacts/ArtifactValidationUtilImpl.java | 73 +++++++++++++++++++ .../IncrementalArtifactsCompiler.java | 18 ++++- .../impl/elements/ManifestFileUtil.java | 2 +- .../nodes/CompositePackagingElementNode.java | 4 +- .../nodes/PackagingTreeNodeFactory.java | 8 +- resources/src/META-INF/IdeaPlugin.xml | 2 + 8 files changed, 159 insertions(+), 18 deletions(-) create mode 100644 java/compiler/impl/src/com/intellij/packaging/impl/artifacts/ArtifactValidationUtil.java create mode 100644 java/compiler/impl/src/com/intellij/packaging/impl/artifacts/ArtifactValidationUtilImpl.java diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/ArtifactUtil.java b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/ArtifactUtil.java index 87170aa1028f..3d246a41c078 100644 --- a/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/ArtifactUtil.java +++ b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/ArtifactUtil.java @@ -105,11 +105,11 @@ public class ArtifactUtil { final @NotNull PackagingElementResolvingContext resolvingContext, final boolean processSubstitutions, final ArtifactType artifactType) { - return processElement(rootElement, type, processor, resolvingContext, processSubstitutions, artifactType, + return processElementRecursively(rootElement, type, processor, resolvingContext, processSubstitutions, artifactType, PackagingElementPath.EMPTY, new HashSet>()); } - private static > boolean processElements(final List> elements, + private static > boolean processElementsRecursively(final List> elements, @Nullable PackagingElementType type, @NotNull PackagingElementProcessor processor, final @NotNull PackagingElementResolvingContext resolvingContext, @@ -117,14 +117,14 @@ public class ArtifactUtil { @NotNull PackagingElementPath path, Set> processed) { for (PackagingElement element : elements) { - if (!processElement(element, type, processor, resolvingContext, processSubstitutions, artifactType, path, processed)) { + if (!processElementRecursively(element, type, processor, resolvingContext, processSubstitutions, artifactType, path, processed)) { return false; } } return true; } - private static > boolean processElement(@NotNull PackagingElement element, @Nullable PackagingElementType type, + private static > boolean processElementRecursively(@NotNull PackagingElement element, @Nullable PackagingElementType type, @NotNull PackagingElementProcessor processor, @NotNull PackagingElementResolvingContext resolvingContext, final boolean processSubstitutions, @@ -140,7 +140,7 @@ public class ArtifactUtil { } if (element instanceof CompositePackagingElement) { final CompositePackagingElement composite = (CompositePackagingElement)element; - return processElements(composite.getChildren(), type, processor, resolvingContext, processSubstitutions, artifactType, + return processElementsRecursively(composite.getChildren(), type, processor, resolvingContext, processSubstitutions, artifactType, path.appendComposite(composite), processed); } else if (element instanceof ComplexPackagingElement && processSubstitutions) { @@ -148,7 +148,7 @@ public class ArtifactUtil { if (processor.shouldProcessSubstitution(complexElement)) { final List> substitution = complexElement.getSubstitution(resolvingContext, artifactType); if (substitution != null) { - return processElements(substitution, type, processor, resolvingContext, processSubstitutions, artifactType, + return processElementsRecursively(substitution, type, processor, resolvingContext, processSubstitutions, artifactType, path.appendComplex(complexElement), processed); } } @@ -207,16 +207,30 @@ public class ArtifactUtil { return VfsUtil.urlToPath(outputUrl) + "/artifacts/" + FileUtil.sanitizeFileName(artifactName); } - public static > boolean processElements(@NotNull List> elements, + public static > boolean processElementsWithSubstitutions(@NotNull List> elements, @NotNull PackagingElementResolvingContext context, @NotNull ArtifactType artifactType, @NotNull PackagingElementPath parentPath, @NotNull PackagingElementProcessor processor) { + return processElementsWithSubstitutions(elements, context, artifactType, parentPath, processor, new HashSet>()); + } + + private static > boolean processElementsWithSubstitutions(@NotNull List> elements, + @NotNull PackagingElementResolvingContext context, + @NotNull ArtifactType artifactType, + @NotNull PackagingElementPath parentPath, + @NotNull PackagingElementProcessor processor, + final Set> processed) { for (PackagingElement element : elements) { + if (!processed.add(element)) { + continue; + } + if (element instanceof ComplexPackagingElement && processor.shouldProcessSubstitution((ComplexPackagingElement)element)) { final ComplexPackagingElement complexElement = (ComplexPackagingElement)element; final List> substitution = complexElement.getSubstitution(context, artifactType); - if (substitution != null && !processElements(substitution, context, artifactType, parentPath.appendComplex(complexElement), processor)) { + if (substitution != null && + !processElementsWithSubstitutions(substitution, context, artifactType, parentPath.appendComplex(complexElement), processor, processed)) { return false; } } @@ -253,7 +267,7 @@ public class ArtifactUtil { final String firstName = i != -1 ? relativePath.substring(0, i) : relativePath; final String tail = i != -1 ? relativePath.substring(i+1) : ""; - return processElements(parent.getChildren(), context, artifactType, parentPath.appendComposite(parent), new PackagingElementProcessor>() { + return processElementsWithSubstitutions(parent.getChildren(), context, artifactType, parentPath.appendComposite(parent), new PackagingElementProcessor>() { @Override public boolean process(@NotNull PackagingElement element, @NotNull PackagingElementPath path) { boolean process = false; @@ -291,7 +305,7 @@ public class ArtifactUtil { public boolean process(@NotNull PackagingElement element, @NotNull PackagingElementPath path) { if (element instanceof DirectoryPackagingElement) { final List> children = ((DirectoryPackagingElement)element).getChildren(); - if (!processElements(children, context, artifactType, path.appendComposite((DirectoryPackagingElement)element), processor)) { + if (!processElementsWithSubstitutions(children, context, artifactType, path.appendComposite((DirectoryPackagingElement)element), processor)) { return false; } } @@ -387,7 +401,7 @@ public class ArtifactUtil { final String tail = i != -1 ? path.substring(i+1) : ""; final List result = new SmartList(); - processElements(parent.getChildren(), context, artifactType, PackagingElementPath.EMPTY, new PackagingElementProcessor>() { + processElementsWithSubstitutions(parent.getChildren(), context, artifactType, PackagingElementPath.EMPTY, new PackagingElementProcessor>() { @Override public boolean process(@NotNull PackagingElement element, @NotNull PackagingElementPath elementPath) { //todo[nik] replace by method findSourceFile() in PackagingElement diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/ArtifactValidationUtil.java b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/ArtifactValidationUtil.java new file mode 100644 index 000000000000..c92a873275cc --- /dev/null +++ b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/ArtifactValidationUtil.java @@ -0,0 +1,34 @@ +/* + * Copyright 2000-2010 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.packaging.impl.artifacts; + +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.project.Project; +import com.intellij.packaging.artifacts.Artifact; +import org.jetbrains.annotations.NotNull; + +import java.util.Set; + +/** + * @author nik + */ +public abstract class ArtifactValidationUtil { + public static ArtifactValidationUtil getInstance(@NotNull Project project) { + return ServiceManager.getService(project, ArtifactValidationUtil.class); + } + + public abstract Set getSelfIncludingArtifacts(); +} diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/ArtifactValidationUtilImpl.java b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/ArtifactValidationUtilImpl.java new file mode 100644 index 000000000000..a09d02aabbf4 --- /dev/null +++ b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/ArtifactValidationUtilImpl.java @@ -0,0 +1,73 @@ +/* + * Copyright 2000-2010 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.packaging.impl.artifacts; + +import com.intellij.openapi.project.Project; +import com.intellij.packaging.artifacts.Artifact; +import com.intellij.packaging.artifacts.ArtifactManager; +import com.intellij.packaging.elements.PackagingElementResolvingContext; +import com.intellij.packaging.impl.elements.ArtifactElementType; +import com.intellij.packaging.impl.elements.ArtifactPackagingElement; +import com.intellij.psi.util.CachedValue; +import com.intellij.psi.util.CachedValueProvider; +import com.intellij.psi.util.CachedValuesManager; +import org.jetbrains.annotations.NotNull; + +import java.util.HashSet; +import java.util.Set; + +/** + * @author nik + */ +public class ArtifactValidationUtilImpl extends ArtifactValidationUtil { + private Project myProject; + private CachedValue> mySelfIncludingArtifacts; + + public ArtifactValidationUtilImpl(Project project) { + myProject = project; + } + + @Override + public Set getSelfIncludingArtifacts() { + if (mySelfIncludingArtifacts == null) { + mySelfIncludingArtifacts = CachedValuesManager.getManager(myProject).createCachedValue(new CachedValueProvider>() { + public Result> compute() { + return Result.create(computeSelfIncludingArtifacts(), ArtifactManager.getInstance(myProject).getModificationTracker()); + } + }, false); + } + return mySelfIncludingArtifacts.getValue(); + } + + private Set computeSelfIncludingArtifacts() { + final ArtifactManager artifactManager = ArtifactManager.getInstance(myProject); + Set result = new HashSet(); + final PackagingElementResolvingContext context = artifactManager.getResolvingContext(); + for (final Artifact artifact : artifactManager.getSortedArtifacts()) { + if (!ArtifactUtil.processPackagingElements(artifact, ArtifactElementType.ARTIFACT_ELEMENT_TYPE, + new PackagingElementProcessor() { + @Override + public boolean process(@NotNull ArtifactPackagingElement element, + @NotNull PackagingElementPath path) { + return !artifact.equals(element.findArtifact(context)); + } + }, context, true)) { + result.add(artifact); + } + } + return result; + } +} diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/compiler/IncrementalArtifactsCompiler.java b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/IncrementalArtifactsCompiler.java index 1ff3398a72e9..bed30dbcba13 100644 --- a/java/compiler/impl/src/com/intellij/packaging/impl/compiler/IncrementalArtifactsCompiler.java +++ b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/IncrementalArtifactsCompiler.java @@ -49,6 +49,7 @@ import com.intellij.packaging.artifacts.ArtifactProperties; import com.intellij.packaging.artifacts.ArtifactPropertiesProvider; import com.intellij.packaging.elements.CompositePackagingElement; import com.intellij.packaging.elements.PackagingElementResolvingContext; +import com.intellij.packaging.impl.artifacts.ArtifactValidationUtil; import com.intellij.testFramework.LightVirtualFile; import com.intellij.util.ArrayUtil; import com.intellij.util.ThrowableRunnable; @@ -121,9 +122,22 @@ public class IncrementalArtifactsCompiler implements PackagingCompiler { public ProcessingItem[] getProcessingItems(final CompileContext context) { return new ReadAction() { protected void run(final Result result) { + final Project project = context.getProject(); + final Set selfIncludingArtifacts = ArtifactValidationUtil.getInstance(project).getSelfIncludingArtifacts(); + if (!selfIncludingArtifacts.isEmpty()) { + LOG.info("Self including artifacts: " + selfIncludingArtifacts); + if (!ArtifactCompileScope.getArtifactsToBuild(project, context.getCompileScope()).isEmpty()) { + for (Artifact artifact : selfIncludingArtifacts) { + context.addMessage(CompilerMessageCategory.ERROR, "Artifact '" + artifact.getName() + "' includes itself in the output layout", null, -1, -1); + } + } + result.setResult(ProcessingItem.EMPTY_ARRAY); + return; + } + ArtifactsProcessingItemsBuilderContext builderContext = new ArtifactsProcessingItemsBuilderContext(context); context.putUserData(BUILDER_CONTEXT_KEY, builderContext); - ArtifactPackagingProcessingItem[] allProcessingItems = collectItems(builderContext, context.getProject()); + ArtifactPackagingProcessingItem[] allProcessingItems = collectItems(builderContext, project); if (LOG.isDebugEnabled()) { int num = Math.min(5000, allProcessingItems.length); @@ -135,7 +149,7 @@ public class IncrementalArtifactsCompiler implements PackagingCompiler { try { final FileProcessingCompilerStateCache cache = - CompilerCacheManager.getInstance(context.getProject()).getFileProcessingCompilerCache(IncrementalArtifactsCompiler.this); + CompilerCacheManager.getInstance(project).getFileProcessingCompilerCache(IncrementalArtifactsCompiler.this); for (ArtifactPackagingProcessingItem item : allProcessingItems) { item.init(cache); } diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/elements/ManifestFileUtil.java b/java/compiler/impl/src/com/intellij/packaging/impl/elements/ManifestFileUtil.java index 3ff8085bf7f7..f326e2f1e831 100644 --- a/java/compiler/impl/src/com/intellij/packaging/impl/elements/ManifestFileUtil.java +++ b/java/compiler/impl/src/com/intellij/packaging/impl/elements/ManifestFileUtil.java @@ -81,7 +81,7 @@ public class ManifestFileUtil { final Ref sourceDir = Ref.create(null); final Ref sourceFile = Ref.create(null); - ArtifactUtil.processElements(root.getChildren(), context, artifactType, PackagingElementPath.EMPTY, new PackagingElementProcessor>() { + ArtifactUtil.processElementsWithSubstitutions(root.getChildren(), context, artifactType, PackagingElementPath.EMPTY, new PackagingElementProcessor>() { @Override public boolean process(@NotNull PackagingElement element, @NotNull PackagingElementPath path) { if (element instanceof FileCopyPackagingElement) { diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/nodes/CompositePackagingElementNode.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/nodes/CompositePackagingElementNode.java index 428639cbe9f7..b252e4442253 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/nodes/CompositePackagingElementNode.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/nodes/CompositePackagingElementNode.java @@ -19,11 +19,13 @@ import com.intellij.openapi.roots.ui.configuration.artifacts.ArtifactEditorImpl; import com.intellij.openapi.roots.ui.configuration.artifacts.ComplexElementSubstitutionParameters; import com.intellij.packaging.artifacts.ArtifactType; import com.intellij.packaging.elements.CompositePackagingElement; +import com.intellij.packaging.elements.PackagingElement; import com.intellij.packaging.ui.ArtifactEditorContext; import com.intellij.ui.treeStructure.SimpleNode; import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; import java.util.List; /** @@ -47,7 +49,7 @@ public class CompositePackagingElementNode extends PackagingElementNode> children = new ArrayList>(); for (CompositePackagingElement element : getPackagingElements()) { PackagingTreeNodeFactory.addNodes(element.getChildren(), this, element, myContext, mySubstitutionParameters, getNodeSource(element), children, - myArtifactType); + myArtifactType, new HashSet>()); } return children.toArray(new SimpleNode[children.size()]); } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/nodes/PackagingTreeNodeFactory.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/nodes/PackagingTreeNodeFactory.java index a9f92fd0347c..a600f98af2ce 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/nodes/PackagingTreeNodeFactory.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/nodes/PackagingTreeNodeFactory.java @@ -29,6 +29,7 @@ import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Set; /** * @author nik @@ -41,7 +42,8 @@ public class PackagingTreeNodeFactory { @NotNull CompositePackagingElement parentElement, @NotNull ArtifactEditorContext context, @NotNull ComplexElementSubstitutionParameters substitutionParameters, @NotNull Collection nodeSources, @NotNull List> nodes, - ArtifactType artifactType) { + ArtifactType artifactType, + Set> processed) { for (PackagingElement element : elements) { final PackagingElementNode prev = findEqual(nodes, element); if (prev != null) { @@ -58,12 +60,12 @@ public class PackagingTreeNodeFactory { } else if (element instanceof ComplexPackagingElement) { final ComplexPackagingElement complexElement = (ComplexPackagingElement)element; - if (substitutionParameters.shouldSubstitute(complexElement)) { + if (processed.add(element) && substitutionParameters.shouldSubstitute(complexElement)) { final List> substitution = complexElement.getSubstitution(context, artifactType); if (substitution != null) { final PackagingNodeSource source = new PackagingNodeSource(complexElement, parentNode, parentElement, nodeSources); addNodes(substitution, parentNode, parentElement, context, substitutionParameters, Collections.singletonList(source), nodes, - artifactType); + artifactType, processed); continue; } } diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index 32d943f92085..53be53b8126f 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -352,6 +352,8 @@ serviceImplementation="com.intellij.packaging.impl.artifacts.ArtifactPointerManagerImpl"/> +