/* * Copyright 2000-2012 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.jps; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.Consumer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.model.JpsDummyElement; import org.jetbrains.jps.model.java.*; import org.jetbrains.jps.model.java.compiler.ProcessorConfigProfile; import org.jetbrains.jps.model.library.JpsOrderRootType; import org.jetbrains.jps.model.library.sdk.JpsSdk; import org.jetbrains.jps.model.module.JpsDependencyElement; import org.jetbrains.jps.model.module.JpsModule; import org.jetbrains.jps.model.module.JpsModuleSourceRoot; import org.jetbrains.jps.model.module.JpsSdkDependency; import org.jetbrains.jps.util.JpsPathUtil; import java.io.File; import java.util.*; /** * @author Eugene Zhuravlev * Date: 9/30/11 */ public class ProjectPaths { private ProjectPaths() { } @NotNull public static Collection getCompilationClasspathFiles(ModuleChunk chunk, boolean includeTests, final boolean excludeMainModuleOutput, final boolean exportedOnly) { return getClasspathFiles(chunk, JpsJavaClasspathKind.compile(includeTests), excludeMainModuleOutput, ClasspathPart.WHOLE, exportedOnly); } @NotNull public static Collection getPlatformCompilationClasspath(ModuleChunk chunk, boolean excludeMainModuleOutput) { return getClasspathFiles(chunk, JpsJavaClasspathKind.compile(chunk.containsTests()), excludeMainModuleOutput, ClasspathPart.BEFORE_JDK, true); } @NotNull public static Collection getCompilationClasspath(ModuleChunk chunk, boolean excludeMainModuleOutput) { return getClasspathFiles(chunk, JpsJavaClasspathKind.compile(chunk.containsTests()), excludeMainModuleOutput, ClasspathPart.AFTER_JDK, true); } @NotNull private static Collection getClasspathFiles(ModuleChunk chunk, JpsJavaClasspathKind kind, final boolean excludeMainModuleOutput, ClasspathPart classpathPart, final boolean exportedOnly) { final Set files = new LinkedHashSet(); for (JpsModule module : chunk.getModules()) { JpsJavaDependenciesEnumerator enumerator = JpsJavaExtensionService.dependencies(module).includedIn(kind).recursively(); if (exportedOnly) { enumerator = enumerator.exportedOnly(); } if (classpathPart == ClasspathPart.BEFORE_JDK) { enumerator = enumerator.satisfying(new BeforeJavaSdkItemFilter(module)); } else if (classpathPart == ClasspathPart.AFTER_JDK) { enumerator = enumerator.satisfying(new AfterJavaSdkItemFilter(module)); } JpsJavaDependenciesRootsEnumerator rootsEnumerator = enumerator.classes(); if (excludeMainModuleOutput) { rootsEnumerator = rootsEnumerator.withoutSelfModuleOutput(); } files.addAll(rootsEnumerator.getRoots()); } if (classpathPart == ClasspathPart.BEFORE_JDK) { for (JpsModule module : chunk.getModules()) { JpsSdk sdk = module.getSdk(JpsJavaSdkType.INSTANCE); if (sdk != null) { files.addAll(sdk.getParent().getFiles(JpsOrderRootType.COMPILED)); } } } return files; } private static void addFile(Set classpath, @Nullable String url) { if (url != null) { classpath.add(JpsPathUtil.urlToFile(url)); } } /** * * @param chunk * @return mapping "sourceRoot" -> "package prefix" Package prefix uses slashes instead of dots and ends with trailing slash */ @NotNull public static Map getSourceRootsWithDependents(ModuleChunk chunk) { final boolean includeTests = chunk.containsTests(); final Map result = new LinkedHashMap(); processModulesRecursively(chunk, JpsJavaClasspathKind.compile(includeTests), new Consumer() { @Override public void consume(JpsModule module) { for (JpsModuleSourceRoot root : module.getSourceRoots()) { if (root.getRootType().equals(JavaSourceRootType.SOURCE) || includeTests && root.getRootType().equals(JavaSourceRootType.TEST_SOURCE)) { String prefix = ((JavaSourceRootProperties)root.getProperties()).getPackagePrefix(); if (!prefix.isEmpty()) { prefix = prefix.replace('.', '/'); if (!prefix.endsWith("/")) { prefix += "/"; } } else { prefix = null; } result.put(JpsPathUtil.urlToFile(root.getUrl()), prefix); } } } }); return result; } public static Collection getOutputPathsWithDependents(final ModuleChunk chunk) { final boolean forTests = chunk.containsTests(); final Set sourcePaths = new LinkedHashSet(); processModulesRecursively(chunk, JpsJavaClasspathKind.compile(forTests), new Consumer() { @Override public void consume(JpsModule module) { addFile(sourcePaths, JpsJavaExtensionService.getInstance().getOutputUrl(module, forTests)); } }); return sourcePaths; } public static Set getModulesWithDependentsRecursively(final JpsModule module, final boolean includeTests) { return JpsJavaExtensionService.dependencies(module).includedIn(JpsJavaClasspathKind.compile(includeTests)).recursively().getModules(); } private static void processModulesRecursively(ModuleChunk chunk, JpsJavaClasspathKind kind, Consumer processor) { JpsJavaExtensionService.getInstance().enumerateDependencies(chunk.getModules()).includedIn(kind).recursively().processModules(processor); } @Nullable public static File getModuleOutputDir(JpsModule module, boolean forTests) { return JpsJavaExtensionService.getInstance().getOutputDirectory(module, forTests); } @Nullable public static File getAnnotationProcessorGeneratedSourcesOutputDir(JpsModule module, final boolean forTests, ProcessorConfigProfile profile) { final String sourceDirName = profile.getGeneratedSourcesDirectoryName(forTests); if (profile.isOutputRelativeToContentRoot()) { List roots = module.getContentRootsList().getUrls(); if (roots.isEmpty()) { return null; } if (roots.size() > 1) { roots = new ArrayList(roots); // sort roots to get deterministic result Collections.sort(roots, new Comparator() { @Override public int compare(String o1, String o2) { return o1.compareTo(o2); } }); } final File parent = JpsPathUtil.urlToFile(roots.get(0)); return StringUtil.isEmpty(sourceDirName)? parent : new File(parent, sourceDirName); } final File outputDir = getModuleOutputDir(module, forTests); if (outputDir == null) { return null; } return StringUtil.isEmpty(sourceDirName)? outputDir : new File(outputDir, sourceDirName); } private enum ClasspathPart {WHOLE, BEFORE_JDK, AFTER_JDK} private static class BeforeJavaSdkItemFilter implements Condition { private JpsModule myModule; private boolean mySdkFound; private BeforeJavaSdkItemFilter(JpsModule module) { myModule = module; } @Override public boolean value(JpsDependencyElement dependency) { boolean isJavaSdk = dependency instanceof JpsSdkDependency && ((JpsSdkDependency)dependency).getSdkType().equals(JpsJavaSdkType.INSTANCE); if (myModule.equals(dependency.getContainingModule()) && isJavaSdk) { mySdkFound = true; } return !mySdkFound && !isJavaSdk; } } private static class AfterJavaSdkItemFilter implements Condition { private JpsModule myModule; private boolean mySdkFound; private AfterJavaSdkItemFilter(JpsModule module) { myModule = module; } @Override public boolean value(JpsDependencyElement dependency) { if (myModule.equals(dependency.getContainingModule())) { if (dependency instanceof JpsSdkDependency && ((JpsSdkDependency)dependency).getSdkType().equals(JpsJavaSdkType.INSTANCE)) { mySdkFound = true; return false; } } return mySdkFound; } } }