in src/com/facebook/buck/command/Project.java [368:524]
private Module createModuleForProjectConfig(ProjectConfigRule projectConfig) throws IOException {
BuildRule projectRule = projectConfig.getProjectRule();
Buildable buildable = projectRule.getBuildable();
Preconditions.checkState(projectRule instanceof JavaLibraryRule
|| projectRule instanceof AndroidLibraryRule
|| projectRule instanceof AndroidResourceRule
|| projectRule instanceof AndroidBinaryRule
|| buildable instanceof NdkLibrary,
"project_config() does not know how to process a src_target of type %s.",
projectRule.getType().getName());
LinkedHashSet<DependentModule> dependencies = Sets.newLinkedHashSet();
final BuildTarget target = projectConfig.getBuildTarget();
Module module = new Module(projectRule, target);
module.name = getIntellijNameForRule(projectRule);
module.isIntelliJPlugin = projectConfig.getIsIntelliJPlugin();
String relativePath = projectConfig.getBuildTarget().getBasePathWithSlash();
module.pathToImlFile = String.format("%s%s.iml", relativePath, module.name);
// List the module source as the first dependency.
boolean includeSourceFolder = true;
// Do the tests before the sources so they appear earlier in the classpath. When tests are run,
// their classpath entries may be deliberately shadowing production classpath entries.
// tests folder
boolean hasSourceFoldersForTestRule = addSourceFolders(module,
projectConfig.getTestRule(),
projectConfig.getTestsSourceRoots(),
true /* isTestSource */);
// test dependencies
BuildRule testRule = projectConfig.getTestRule();
if (testRule != null) {
walkRuleAndAdd(testRule, true /* isForTests */, dependencies, projectConfig.getSrcRule());
}
// src folder
boolean hasSourceFoldersForSrcRule = addSourceFolders(module,
projectConfig.getSrcRule(),
projectConfig.getSourceRoots(),
false /* isTestSource */);
// At least one of src or tests should contribute a source folder unless this is an
// non-library Android project with no source roots specified.
if (!hasSourceFoldersForTestRule && !hasSourceFoldersForSrcRule) {
includeSourceFolder = false;
}
// IntelliJ expects all Android projects to have a gen/ folder, even if there is no src/
// directory specified.
boolean isAndroidRule = projectRule.getProperties().is(ANDROID);
if (isAndroidRule) {
boolean hasSourceFolders = !module.sourceFolders.isEmpty();
module.sourceFolders.add(SourceFolder.GEN);
if (!hasSourceFolders) {
includeSourceFolder = true;
}
}
// src dependencies
// Note that isForTests is false even if projectRule is the project_config's test_target.
walkRuleAndAdd(projectRule, false /* isForTests */, dependencies, projectConfig.getSrcRule());
String basePathWithSlash = projectConfig.getBuildTarget().getBasePathWithSlash();
// Specify another path for intellij to generate gen/ for each android module,
// so that it will not disturb our glob() rules.
// To specify the location of gen, Intellij requires the relative path from
// the base path of current build target.
module.moduleGenPath = generateRelativeGenPath(basePathWithSlash).toString();
DependentModule jdkDependency;
if (isAndroidRule) {
// android details
if (projectRule.getBuildable() instanceof NdkLibrary) {
NdkLibrary ndkLibrary = (NdkLibrary) projectRule.getBuildable();
module.isAndroidLibraryProject = true;
module.keystorePath = null;
module.nativeLibs = Paths.get(relativePath).relativize(Paths.get(ndkLibrary.getLibraryPath())).toString();
} else if (projectRule instanceof AndroidResourceRule) {
AndroidResourceRule androidResourceRule = (AndroidResourceRule)projectRule;
module.resFolder = createRelativePath(androidResourceRule.getRes(), target);
module.isAndroidLibraryProject = true;
module.keystorePath = null;
} else if (projectRule instanceof AndroidBinaryRule) {
AndroidBinaryRule androidBinaryRule = (AndroidBinaryRule)projectRule;
module.resFolder = null;
module.isAndroidLibraryProject = false;
KeystoreProperties keystoreProperties = KeystoreProperties.createFromPropertiesFile(
androidBinaryRule.getKeystore().getPathToStore(),
androidBinaryRule.getKeystore().getPathToPropertiesFile(),
projectFilesystem);
// getKeystore() returns a path relative to the project root, but an IntelliJ module
// expects the path to the keystore to be relative to the module root.
module.keystorePath = Paths.get(relativePath).relativize(Paths.get(keystoreProperties.getKeystore())).toString();
} else {
module.isAndroidLibraryProject = true;
module.keystorePath = null;
}
module.hasAndroidFacet = true;
module.proguardConfigPath = null;
// If there is a default AndroidManifest.xml specified in .buckconfig, use it if
// AndroidManifest.xml is not present in the root of the [Android] IntelliJ module.
if (pathToDefaultAndroidManifest.isPresent()) {
String androidManifest = basePathWithSlash + "AndroidManifest.xml";
if (!projectFilesystem.exists(androidManifest)) {
String manifestPath = this.pathToDefaultAndroidManifest.get();
String rootPrefix = "//";
Preconditions.checkState(manifestPath.startsWith(rootPrefix),
"Currently, we expect this option to start with '%s', " +
"indicating that it is relative to the root of the repository.",
rootPrefix);
manifestPath = manifestPath.substring(rootPrefix.length());
String relativePathToManifest = Paths.get(basePathWithSlash).relativize(Paths.get(manifestPath)).toString();
// IntelliJ requires that the path start with a slash to indicate that it is relative to
// the module.
module.androidManifest = "/" + relativePathToManifest;
}
}
// List this last so that classes from modules can shadow classes in the JDK.
jdkDependency = DependentModule.newInheritedJdk();
} else {
module.hasAndroidFacet = false;
if (module.isIntelliJPlugin()) {
jdkDependency = DependentModule.newIntelliJPluginJdk();
} else {
jdkDependency = DependentModule.newStandardJdk();
}
}
// Assign the dependencies.
module.dependencies = createDependenciesInOrder(
includeSourceFolder, dependencies, jdkDependency);
// Annotation processing generates sources for IntelliJ to consume, but does so outside
// the module directory to avoid messing up globbing.
if (projectRule instanceof JavaLibraryRule) {
JavaLibraryRule javaLibraryRule = (JavaLibraryRule)projectRule;
AnnotationProcessingData processingData = javaLibraryRule.getAnnotationProcessingData();
String annotationGenSrc = processingData.getGeneratedSourceFolderName();
if (annotationGenSrc != null) {
module.annotationGenPath =
"/" + Paths.get(basePathWithSlash).relativize(Paths.get(annotationGenSrc)).toString();
module.annotationGenIsForTest = !hasSourceFoldersForSrcRule;
}
}
return module;
}