blob: 962f6d81cbe9891affe2a10fce9ae96babad7384 [file] [log] [blame]
/*
* 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<File> 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<File> getPlatformCompilationClasspath(ModuleChunk chunk, boolean excludeMainModuleOutput) {
return getClasspathFiles(chunk, JpsJavaClasspathKind.compile(chunk.containsTests()), excludeMainModuleOutput, ClasspathPart.BEFORE_JDK, true);
}
@NotNull
public static Collection<File> getCompilationClasspath(ModuleChunk chunk, boolean excludeMainModuleOutput) {
return getClasspathFiles(chunk, JpsJavaClasspathKind.compile(chunk.containsTests()), excludeMainModuleOutput, ClasspathPart.AFTER_JDK, true);
}
@NotNull
private static Collection<File> getClasspathFiles(ModuleChunk chunk,
JpsJavaClasspathKind kind,
final boolean excludeMainModuleOutput,
ClasspathPart classpathPart, final boolean exportedOnly) {
final Set<File> files = new LinkedHashSet<File>();
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<JpsDummyElement> sdk = module.getSdk(JpsJavaSdkType.INSTANCE);
if (sdk != null) {
files.addAll(sdk.getParent().getFiles(JpsOrderRootType.COMPILED));
}
}
}
return files;
}
private static void addFile(Set<File> 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<File, String> getSourceRootsWithDependents(ModuleChunk chunk) {
final boolean includeTests = chunk.containsTests();
final Map<File, String> result = new LinkedHashMap<File, String>();
processModulesRecursively(chunk, JpsJavaClasspathKind.compile(includeTests), new Consumer<JpsModule>() {
@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<File> getOutputPathsWithDependents(final ModuleChunk chunk) {
final boolean forTests = chunk.containsTests();
final Set<File> sourcePaths = new LinkedHashSet<File>();
processModulesRecursively(chunk, JpsJavaClasspathKind.compile(forTests), new Consumer<JpsModule>() {
@Override
public void consume(JpsModule module) {
addFile(sourcePaths, JpsJavaExtensionService.getInstance().getOutputUrl(module, forTests));
}
});
return sourcePaths;
}
public static Set<JpsModule> 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<JpsModule> 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<String> roots = module.getContentRootsList().getUrls();
if (roots.isEmpty()) {
return null;
}
if (roots.size() > 1) {
roots = new ArrayList<String>(roots); // sort roots to get deterministic result
Collections.sort(roots, new Comparator<String>() {
@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<JpsDependencyElement> {
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<JpsDependencyElement> {
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;
}
}
}