diff --git a/java/execution/openapi/src/com/intellij/execution/configurations/JavaParameters.java b/java/execution/openapi/src/com/intellij/execution/configurations/JavaParameters.java index 2f4ac36f2b2c..e137c332dfe0 100644 --- a/java/execution/openapi/src/com/intellij/execution/configurations/JavaParameters.java +++ b/java/execution/openapi/src/com/intellij/execution/configurations/JavaParameters.java @@ -18,13 +18,11 @@ package com.intellij.execution.configurations; import com.intellij.execution.CantRunException; import com.intellij.execution.ExecutionBundle; import com.intellij.openapi.actionSystem.DataKey; -import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.roots.ModuleRootManager; -import com.intellij.openapi.roots.ProjectClasspathTraversing; -import com.intellij.openapi.roots.ProjectRootsTraversing; +import com.intellij.openapi.roots.OrderEnumerator; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.encoding.EncodingProjectManager; @@ -66,7 +64,7 @@ public class JavaParameters extends SimpleJavaParameters { } setDefaultCharset(module.getProject()); - ProjectRootsTraversing.collectRoots(module, getPolicy(null, module, classPathType), getClassPath()); + configureEnumerator(OrderEnumerator.orderEntries(module).runtimeOnly().recursively(), classPathType).collectPaths(getClassPath()); } public void setDefaultCharset(final Project project) { @@ -104,22 +102,16 @@ public class JavaParameters extends SimpleJavaParameters { return; } - ProjectRootsTraversing.collectRoots(project, getPolicy(project, null, classPathType), getClassPath()); + configureEnumerator(OrderEnumerator.orderEntries(project).runtimeOnly(), classPathType).collectPaths(getClassPath()); } - private ProjectRootsTraversing.RootTraversePolicy getPolicy(Project project, Module module, int classPathType) { - ProjectRootsTraversing.RootTraversePolicy result = (classPathType & TESTS_ONLY) != 0 - ? (classPathType & JDK_ONLY) != 0 ? ProjectClasspathTraversing.FULL_CLASSPATH_RECURSIVE : ProjectClasspathTraversing.FULL_CLASS_RECURSIVE_WO_JDK - : (classPathType & JDK_ONLY) != 0 ? ProjectClasspathTraversing.FULL_CLASSPATH_WITHOUT_TESTS : ProjectClasspathTraversing.FULL_CLASSPATH_WITHOUT_JDK_AND_TESTS; - - for (JavaClasspathPolicyExtender each : Extensions.getExtensions(JavaClasspathPolicyExtender.EP_NAME)) { - if (project == null) { - result = each.extend(module, result); - } - else { - result = each.extend(project, result); - } + private static OrderEnumerator configureEnumerator(OrderEnumerator enumerator, int classPathType) { + if ((classPathType & JDK_ONLY) == 0) { + enumerator = enumerator.withoutSdk(); } - return result; + if ((classPathType & TESTS_ONLY) == 0) { + enumerator = enumerator.productionOnly(); + } + return enumerator; } } \ No newline at end of file diff --git a/platform/lang-api/src/com/intellij/openapi/roots/OrderEnumerationHandler.java b/platform/lang-api/src/com/intellij/openapi/roots/OrderEnumerationHandler.java new file mode 100644 index 000000000000..9c5378ab29c3 --- /dev/null +++ b/platform/lang-api/src/com/intellij/openapi/roots/OrderEnumerationHandler.java @@ -0,0 +1,43 @@ +/* + * 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.openapi.roots; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * @author nik + */ +public abstract class OrderEnumerationHandler { + public static final ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.orderEnumerationHandler"); + + public abstract boolean isApplicable(@NotNull Project project); + + public abstract boolean isApplicable(@NotNull Module module); + + public boolean shouldProcessRecursively(@NotNull ModuleOrderEntry dependency) { + return true; + } + + public boolean addCustomOutput(@NotNull ModuleOrderEntry orderEntry, boolean productionOnly, @NotNull List result) { + return false; + } +} diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/impl/ModuleOrderEnumerator.java b/platform/lang-impl/src/com/intellij/openapi/roots/impl/ModuleOrderEnumerator.java index 7bc14498e93d..b06d6879865a 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/impl/ModuleOrderEnumerator.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/impl/ModuleOrderEnumerator.java @@ -27,6 +27,7 @@ public class ModuleOrderEnumerator extends OrderEnumeratorBase { private final RootModelImpl myRootModel; public ModuleOrderEnumerator(RootModelImpl rootModel) { + super(rootModel.getModule(), rootModel.getProject()); myRootModel = rootModel; } diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/impl/OrderEnumeratorBase.java b/platform/lang-impl/src/com/intellij/openapi/roots/impl/OrderEnumeratorBase.java index c25ca96dfc94..29b8138e4cca 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/impl/OrderEnumeratorBase.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/impl/OrderEnumeratorBase.java @@ -16,12 +16,16 @@ package com.intellij.openapi.roots.impl; import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.*; import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.util.Condition; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.PathsList; import com.intellij.util.Processor; +import com.intellij.util.SmartList; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.*; @@ -40,6 +44,18 @@ public abstract class OrderEnumeratorBase extends OrderEnumerator { private boolean myRecursivelyExportedOnly; private boolean myExportedOnly; private Condition myCondition; + private List myCustomHandlers; + + public OrderEnumeratorBase(@Nullable Module module, @NotNull Project project) { + for (OrderEnumerationHandler handler : OrderEnumerationHandler.EP_NAME.getExtensions()) { + if (handler.isApplicable(project) && (module == null || handler.isApplicable(module))) { + if (myCustomHandlers == null) { + myCustomHandlers = new SmartList(); + } + myCustomHandlers.add(handler); + } + } + } @Override public OrderEnumerator productionOnly() { @@ -148,12 +164,21 @@ public abstract class OrderEnumeratorBase extends OrderEnumerator { forEach(new Processor() { @Override public boolean process(OrderEntry orderEntry) { + final Module ownerModule = orderEntry.getOwnerModule(); if (orderEntry instanceof ModuleSourceOrderEntry) { collectModulePaths(((ModuleSourceOrderEntry)orderEntry).getRootModel(), list, collectSources); } else if (orderEntry instanceof ModuleOrderEntry) { - final Module module = ((ModuleOrderEntry)orderEntry).getModule(); + ModuleOrderEntry moduleOrderEntry = (ModuleOrderEntry)orderEntry; + final Module module = moduleOrderEntry.getModule(); if (module != null) { + if (myCustomHandlers != null) { + for (OrderEnumerationHandler handler : myCustomHandlers) { + if (handler.addCustomOutput(moduleOrderEntry, myProductionOnly, list)) { + return true; + } + } + } collectModulePaths(ModuleRootManager.getInstance(module), list, collectSources); } } @@ -179,9 +204,13 @@ public abstract class OrderEnumeratorBase extends OrderEnumerator { if (entry instanceof ExportableOrderEntry) { ExportableOrderEntry exportableEntry = (ExportableOrderEntry)entry; final DependencyScope scope = exportableEntry.getScope(); - if (myProductionOnly && !scope.isForProductionCompile() && !scope.isForProductionRuntime()) continue; if (myCompileOnly && !scope.isForProductionCompile() && !scope.isForTestCompile()) continue; if (myRuntimeOnly && !scope.isForProductionRuntime() && !scope.isForTestRuntime()) continue; + if (myProductionOnly) { + if (!scope.isForProductionCompile() && !scope.isForProductionRuntime() + || myCompileOnly && !scope.isForProductionCompile() + || myRuntimeOnly && !scope.isForProductionRuntime()) continue; + } if (!exportableEntry.isExported()) { if (myExportedOnly) continue; if (myRecursivelyExportedOnly && !firstLevel) continue; @@ -191,10 +220,23 @@ public abstract class OrderEnumeratorBase extends OrderEnumerator { if (myCondition != null && !myCondition.value(entry)) continue; if (myRecursively && entry instanceof ModuleOrderEntry) { - final Module module = ((ModuleOrderEntry)entry).getModule(); + ModuleOrderEntry moduleOrderEntry = (ModuleOrderEntry)entry; + final Module module = moduleOrderEntry.getModule(); if (module != null) { - processEntries(ModuleRootManager.getInstance(module), processor, processed, false); - continue; + boolean processRecursively = true; + if (myCustomHandlers != null) { + for (OrderEnumerationHandler handler : myCustomHandlers) { + if (!handler.shouldProcessRecursively(moduleOrderEntry)) { + processRecursively = false; + break; + } + } + } + + if (processRecursively) { + processEntries(ModuleRootManager.getInstance(module), processor, processed, false); + continue; + } } } diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/impl/ProjectOrderEnumerator.java b/platform/lang-impl/src/com/intellij/openapi/roots/impl/ProjectOrderEnumerator.java index 65c12076ee14..61d67439ab42 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/impl/ProjectOrderEnumerator.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/impl/ProjectOrderEnumerator.java @@ -30,6 +30,7 @@ public class ProjectOrderEnumerator extends OrderEnumeratorBase { private Project myProject; public ProjectOrderEnumerator(Project project) { + super(null, project); myProject = project; } diff --git a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml index 140130775d16..1405d1c09505 100644 --- a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml @@ -142,6 +142,7 @@ + diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenJavaClasspathPolicyExtender.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenJavaClasspathPolicyExtender.java deleted file mode 100644 index 04ae3b1f4b9e..000000000000 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenJavaClasspathPolicyExtender.java +++ /dev/null @@ -1,98 +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 org.jetbrains.idea.maven.execution; - -import com.intellij.execution.configurations.JavaClasspathPolicyExtender; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.roots.*; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.idea.maven.model.MavenArtifact; -import org.jetbrains.idea.maven.model.MavenConstants; -import org.jetbrains.idea.maven.project.MavenProject; -import org.jetbrains.idea.maven.project.MavenProjectsManager; - -import java.util.Collections; - -public class MavenJavaClasspathPolicyExtender implements JavaClasspathPolicyExtender { - @NotNull - public ProjectRootsTraversing.RootTraversePolicy extend(Project project, @NotNull ProjectRootsTraversing.RootTraversePolicy policy) { - return policy; - } - - @NotNull - public ProjectRootsTraversing.RootTraversePolicy extend(final Module module, @NotNull ProjectRootsTraversing.RootTraversePolicy policy) { - Project project = module.getProject(); - final MavenProjectsManager manager = MavenProjectsManager.getInstance(project); - if (!manager.isMavenizedProject() || !manager.isMavenizedModule(module)) return policy; - - return new ProjectRootsTraversing.RootTraversePolicy(extend(module, manager, policy.getVisitSource(), false), - policy.getVisitJdk(), - extend(module, manager, policy.getVisitLibrary(), true), - extend(module, manager, policy.getVisitModule(), true)); - } - - private ProjectRootsTraversing.RootTraversePolicy.Visit extend( - final Module originalModule, - final MavenProjectsManager manager, - final ProjectRootsTraversing.RootTraversePolicy.Visit original, - final boolean skipDependencyModules) { - - return new ProjectRootsTraversing.RootTraversePolicy.Visit() { - public void visit(T entry, ProjectRootsTraversing.TraverseState state, RootPolicy policy) { - Module ownerModule = entry.getOwnerModule(); - if (skipDependencyModules && originalModule != ownerModule) return; - - if (originalModule != ownerModule && entry instanceof ModuleSourceOrderEntry) { - MavenProject project = manager.findProject(originalModule); - MavenProject depProject = manager.findProject(ownerModule); - - if (project == null || depProject == null) { - original.visit(entry, state, policy); - return; - } - - for (MavenArtifact each : project.findDependencies(depProject)) { - boolean isTestClasspath = original == ProjectClasspathTraversing.ALL_OUTPUTS; - - if (!isTestClasspath && MavenConstants.SCOPE_PROVIDEED.equals(each.getScope())) continue; - if (isTestClasspath || !MavenConstants.SCOPE_TEST.equals(each.getScope())) { - boolean isTestJar = MavenConstants.TYPE_TEST_JAR.equals(each.getType()) || "tests".equals(each.getClassifier()); - addOutput(ownerModule, isTestJar, state); - } - } - } - else { - // should be in some generic place - if (entry instanceof ExportableOrderEntry) { - boolean isTestClasspath = original == ProjectRootsTraversing.RootTraversePolicy.ADD_CLASSES - || original == ProjectRootsTraversing.RootTraversePolicy.RECURSIVE; - if (!isTestClasspath && ((ExportableOrderEntry)entry).getScope() == DependencyScope.PROVIDED) return; - } - original.visit(entry, state, policy); - } - } - }; - } - - public void addOutput(Module module, boolean tests, ProjectRootsTraversing.TraverseState state) { - CompilerModuleExtension ex = CompilerModuleExtension.getInstance(module); - if (ex == null) return; - - String output = tests ? ex.getCompilerOutputUrlForTests() : ex.getCompilerOutputUrl(); - if (output != null) state.addAllUrls(Collections.singletonList(output)); - } -} diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenOrderEnumeratorHandler.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenOrderEnumeratorHandler.java new file mode 100644 index 000000000000..9bde6f9599b4 --- /dev/null +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenOrderEnumeratorHandler.java @@ -0,0 +1,87 @@ +/* + * 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 org.jetbrains.idea.maven.execution; + +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.CompilerModuleExtension; +import com.intellij.openapi.roots.ModuleOrderEntry; +import com.intellij.openapi.roots.OrderEnumerationHandler; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.maven.model.MavenArtifact; +import org.jetbrains.idea.maven.model.MavenConstants; +import org.jetbrains.idea.maven.project.MavenProject; +import org.jetbrains.idea.maven.project.MavenProjectsManager; + +import java.util.List; + +/** + * @author nik + */ +public class MavenOrderEnumeratorHandler extends OrderEnumerationHandler { + @Override + public boolean isApplicable(@NotNull Project project) { + return MavenProjectsManager.getInstance(project).isMavenizedProject(); + } + + @Override + public boolean isApplicable(@NotNull Module module) { + final MavenProjectsManager manager = MavenProjectsManager.getInstance(module.getProject()); + return manager.isMavenizedModule(module); + } + + @Override + public boolean shouldProcessRecursively(@NotNull ModuleOrderEntry dependency) { + return false; + } + + @Override + public boolean addCustomOutput(@NotNull ModuleOrderEntry orderEntry, + boolean productionOnly, + @NotNull List result) { + final Module ownerModule = orderEntry.getOwnerModule(); + final Module depModule = orderEntry.getModule(); + if (depModule == null) return false; + + final MavenProjectsManager manager = MavenProjectsManager.getInstance(ownerModule.getProject()); + MavenProject project = manager.findProject(ownerModule); + MavenProject depProject = manager.findProject(depModule); + if (project == null || depProject == null) { + return false; + } + + for (MavenArtifact each : project.findDependencies(depProject)) { + + if (productionOnly && MavenConstants.SCOPE_PROVIDEED.equals(each.getScope())) continue; + if (productionOnly && MavenConstants.SCOPE_TEST.equals(each.getScope())) continue; + + boolean isTestJar = MavenConstants.TYPE_TEST_JAR.equals(each.getType()) || "tests".equals(each.getClassifier()); + addOutput(depModule, isTestJar, result); + } + return true; + } + + private static void addOutput(Module module, boolean tests, List result) { + CompilerModuleExtension ex = CompilerModuleExtension.getInstance(module); + if (ex == null) return; + + VirtualFile output = tests ? ex.getCompilerOutputPathForTests() : ex.getCompilerOutputPath(); + if (output != null) { + result.add(output); + } + } +} diff --git a/plugins/maven/src/main/resources/META-INF/plugin.xml b/plugins/maven/src/main/resources/META-INF/plugin.xml index e5ee12fc523f..94e13872e48e 100644 --- a/plugins/maven/src/main/resources/META-INF/plugin.xml +++ b/plugins/maven/src/main/resources/META-INF/plugin.xml @@ -30,7 +30,7 @@ - + diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/execution/JavaClasspathConfigurationTest.java b/plugins/maven/src/test/java/org/jetbrains/idea/maven/execution/JavaClasspathConfigurationTest.java index a8f2349e1407..3d86fb3cfd3f 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/execution/JavaClasspathConfigurationTest.java +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/execution/JavaClasspathConfigurationTest.java @@ -18,17 +18,22 @@ package org.jetbrains.idea.maven.execution; import com.intellij.execution.CantRunException; import com.intellij.execution.configurations.JavaParameters; import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.roots.CompilerModuleExtension; import com.intellij.openapi.roots.ModifiableRootModel; import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileManager; import junit.framework.Test; import junit.framework.TestSuite; +import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.maven.MavenImportingTestCase; import java.io.File; +import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -304,6 +309,7 @@ public class JavaClasspathConfigurationTest extends MavenImportingTestCase { } public void testOptionalLibraryDependencies() throws Exception { + createRepositoryFile("jmock/jmock/1.0/jmock-1.0.jar"); VirtualFile m1 = createModulePom("m1", "test" + "m1" + "1" + @@ -419,6 +425,7 @@ public class JavaClasspathConfigurationTest extends MavenImportingTestCase { } public void testDoNotIncludeProvidedAndTestDependenciesInProductionClasspath() throws Exception { + createRepositoryFile("jmock/jmock/4.0/jmock-4.0.jar"); VirtualFile m1 = createModulePom("m1", "test" + "m1" + "1" + @@ -479,6 +486,7 @@ public class JavaClasspathConfigurationTest extends MavenImportingTestCase { } public void testDoNotIncludeProvidedAndTestTransitiveDependencies() throws Exception { + createRepositoryFile("jmock/jmock/1.0/jmock-1.0.jar"); VirtualFile m1 = createModulePom("m1", "test" + "m1" + "1" + @@ -604,6 +612,7 @@ public class JavaClasspathConfigurationTest extends MavenImportingTestCase { } private void assertModuleClasspath(String moduleName, int classpathType, String... paths) throws CantRunException { + createOutputDirectories(); JavaParameters params = new JavaParameters(); params.configureByModule(getModule(moduleName), classpathType); List systemPaths = new ArrayList(); @@ -612,4 +621,31 @@ public class JavaClasspathConfigurationTest extends MavenImportingTestCase { } assertOrderedElementsAreEqual(params.getClassPath().getPathList(), systemPaths); } + + private void createRepositoryFile(String filePath) throws IOException { + createProjectSubFile("repo/" + filePath); + setRepositoryPath(createProjectSubDir("repo").getPath()); + } + + private void createOutputDirectories() { + for (Module module : ModuleManager.getInstance(myProject).getModules()) { + final CompilerModuleExtension extension = CompilerModuleExtension.getInstance(module); + if (extension != null) { + createDirectoryIfDoesntExist(extension.getCompilerOutputUrl()); + createDirectoryIfDoesntExist(extension.getCompilerOutputUrlForTests()); + } + } + } + + private static void createDirectoryIfDoesntExist(@Nullable String url) { + if (StringUtil.isEmpty(url)) return; + + File file = new File(FileUtil.toSystemDependentName(VfsUtil.urlToPath(url))); + if (file.exists()) return; + + if (!file.mkdirs()) { + fail("Cannot create directory " + file); + } + VirtualFileManager.getInstance().refreshAndFindFileByUrl(url); + } }