use of com.facebook.buck.android.AndroidBinary in project buck by facebook.
the class Project method markNoDxJarsAsProvided.
/**
* Modifies the {@code scope} of a library dependency to {@code "PROVIDED"}, where appropriate.
* <p>
* If an {@code android_binary()} rule uses the {@code no_dx} argument, then the jars in the
* libraries that should not be dex'ed must be included with {@code scope="PROVIDED"} in
* IntelliJ.
* <p>
* The problem is that if a library is included by two android_binary rules that each need it in a
* different way (i.e., for one it should be {@code scope="COMPILE"} and another it should be
* {@code scope="PROVIDED"}), then it must be tagged as {@code scope="PROVIDED"} in all
* dependent modules and then added as {@code scope="COMPILE"} in the .iml file that corresponds
* to the android_binary that <em>does not</em> list the library in its {@code no_dx} list.
*/
@VisibleForTesting
static void markNoDxJarsAsProvided(ProjectFilesystem projectFilesystem, List<SerializableModule> modules, Set<Path> noDxJars, SourcePathResolver resolver) {
Map<String, Path> intelliJLibraryNameToJarPath = Maps.newHashMap();
for (Path jarPath : noDxJars) {
String libraryName = getIntellijNameForBinaryJar(jarPath);
intelliJLibraryNameToJarPath.put(libraryName, jarPath);
}
for (SerializableModule module : modules) {
// For an android_binary() rule, create a set of paths to JAR files (or directories) that
// must be dex'ed. If a JAR file that is in the no_dx list for some android_binary rule, but
// is in this set for this android_binary rule, then it should be scope="COMPILE" rather than
// scope="PROVIDED".
Set<Path> classpathEntriesToDex;
if (module.srcRule instanceof AndroidBinary) {
AndroidBinary androidBinary = (AndroidBinary) module.srcRule;
AndroidPackageableCollection packageableCollection = androidBinary.getAndroidPackageableCollection();
classpathEntriesToDex = new HashSet<>(Sets.intersection(noDxJars, FluentIterable.from(packageableCollection.getClasspathEntriesToDex()).transform(resolver::getAbsolutePath).transform(projectFilesystem::relativize).toSet()));
} else {
classpathEntriesToDex = ImmutableSet.of();
}
// noDxJars, then either change its scope to "COMPILE" or "PROVIDED", as appropriate.
for (SerializableDependentModule dependentModule : Preconditions.checkNotNull(module.getDependencies())) {
if (!dependentModule.isLibrary()) {
continue;
}
// This is the IntelliJ name for the library that corresponds to the PrebuiltJarRule.
String libraryName = dependentModule.getLibraryName();
Path jarPath = intelliJLibraryNameToJarPath.get(libraryName);
if (jarPath != null) {
if (classpathEntriesToDex.contains(jarPath)) {
dependentModule.scope = null;
classpathEntriesToDex.remove(jarPath);
} else {
dependentModule.scope = "PROVIDED";
}
}
}
// if it has not already been added to the module.
for (Path entry : classpathEntriesToDex) {
String libraryName = getIntellijNameForBinaryJar(entry);
SerializableDependentModule dependency = SerializableDependentModule.newLibrary(null, libraryName);
Preconditions.checkNotNull(module.getDependencies()).add(dependency);
}
}
}
use of com.facebook.buck.android.AndroidBinary in project buck by facebook.
the class Project method createModuleForProjectConfig.
@SuppressWarnings("PMD.LooseCoupling")
private SerializableModule createModuleForProjectConfig(ProjectConfig projectConfig, Optional<Path> rJava) throws IOException {
BuildRule projectRule = Preconditions.checkNotNull(projectConfig.getProjectRule());
Preconditions.checkState(projectRule instanceof AndroidBinary || projectRule instanceof AndroidLibrary || projectRule instanceof AndroidResource || projectRule instanceof JavaBinary || projectRule instanceof JavaLibrary || projectRule instanceof JavaTest || projectRule instanceof CxxLibrary || projectRule instanceof NdkLibrary, "project_config() does not know how to process a src_target of type %s (%s).", projectRule.getType(), projectRule.getBuildTarget());
LinkedHashSet<SerializableDependentModule> dependencies = Sets.newLinkedHashSet();
final BuildTarget target = projectConfig.getBuildTarget();
SerializableModule module = new SerializableModule(projectRule, target);
module.name = getIntellijNameForRule(projectRule);
module.isIntelliJPlugin = projectConfig.getIsIntelliJPlugin();
Path relativePath = projectConfig.getBuildTarget().getBasePath();
module.pathToImlFile = relativePath.resolve(module.name + ".iml");
// 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);
// 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);
addRootExcludes(module, projectConfig.getSrcRule(), projectFilesystem);
// 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(SerializableModule.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());
Path basePath = projectConfig.getBuildTarget().getBasePath();
// 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(projectFilesystem, basePath);
if (turnOffAutoSourceGeneration && rJava.isPresent()) {
module.moduleRJavaPath = basePath.relativize(Paths.get("")).resolve(rJava.get());
}
SerializableDependentModule jdkDependency;
if (isAndroidRule) {
// android details
if (projectRule instanceof NdkLibrary) {
NdkLibrary ndkLibrary = (NdkLibrary) projectRule;
module.isAndroidLibraryProject = true;
module.keystorePath = null;
module.nativeLibs = relativePath.relativize(ndkLibrary.getLibraryPath());
} else if (projectRule instanceof AndroidLibrary) {
module.isAndroidLibraryProject = true;
module.keystorePath = null;
module.resFolder = intellijConfig.getAndroidResources().orElse(null);
module.assetFolder = intellijConfig.getAndroidAssets().orElse(null);
} else if (projectRule instanceof AndroidResource) {
AndroidResource androidResource = (AndroidResource) projectRule;
module.resFolder = createRelativeResourcesPath(Optional.ofNullable(androidResource.getRes()).map(resolver::getAbsolutePath).map(projectFilesystem::relativize).orElse(null), target);
module.isAndroidLibraryProject = true;
module.keystorePath = null;
} else if (projectRule instanceof AndroidBinary) {
AndroidBinary androidBinary = (AndroidBinary) projectRule;
module.resFolder = intellijConfig.getAndroidResources().orElse(null);
module.assetFolder = intellijConfig.getAndroidAssets().orElse(null);
module.isAndroidLibraryProject = false;
module.binaryPath = generateRelativeAPKPath(projectFilesystem, projectRule.getBuildTarget().getShortName(), basePath);
KeystoreProperties keystoreProperties = KeystoreProperties.createFromPropertiesFile(resolver.getAbsolutePath(androidBinary.getKeystore().getPathToStore()), resolver.getRelativePath(androidBinary.getKeystore().getPathToPropertiesFile()), projectFilesystem);
// getKeystore() returns an absolute path, but an IntelliJ module
// expects the path to the keystore to be relative to the module root.
// First, grab the aboslute path to the project config.
BuildTarget projectTarget = projectConfig.getBuildTarget();
Path modulePath = projectTarget.getCellPath().resolve(projectTarget.getBasePath());
// Now relativize to the keystore path, which is absolute too.
module.keystorePath = modulePath.relativize(keystoreProperties.getKeystore());
} else {
module.isAndroidLibraryProject = true;
module.keystorePath = null;
}
module.hasAndroidFacet = true;
module.proguardConfigPath = null;
module.androidManifest = resolveAndroidManifestRelativePath(basePath);
// List this last so that classes from modules can shadow classes in the JDK.
jdkDependency = SerializableDependentModule.newInheritedJdk();
} else {
module.hasAndroidFacet = false;
if (module.isIntelliJPlugin()) {
jdkDependency = SerializableDependentModule.newIntelliJPluginJdk();
} else {
jdkDependency = SerializableDependentModule.newStandardJdk(intellijConfig.getJdkName(), intellijConfig.getJdkType());
}
}
// Assign the dependencies.
module.setModuleDependencies(createDependenciesInOrder(includeSourceFolder, dependencies, jdkDependency));
// Annotation processing generates sources for IntelliJ to consume, but does so outside
// the module directory to avoid messing up globbing.
JavaLibrary javaLibrary = null;
if (projectRule instanceof JavaLibrary) {
javaLibrary = (JavaLibrary) projectRule;
}
if (javaLibrary != null) {
Optional<Path> processingParams = javaLibrary.getGeneratedSourcePath();
if (processingParams.isPresent()) {
module.annotationGenPath = basePath.relativize(processingParams.get());
module.annotationGenIsForTest = !hasSourceFoldersForSrcRule;
}
}
return module;
}
use of com.facebook.buck.android.AndroidBinary in project buck by facebook.
the class Project method createModulesForProjectConfigs.
@VisibleForTesting
List<SerializableModule> createModulesForProjectConfigs() throws IOException {
List<SerializableModule> modules = Lists.newArrayList();
// Convert the project_config() targets into modules and find the union of all jars passed to
// no_dx.
ImmutableSet.Builder<Path> noDxJarsBuilder = ImmutableSet.builder();
for (ProjectConfig projectConfig : rules) {
BuildRule srcRule = projectConfig.getSrcRule();
if (srcRule instanceof AndroidBinary) {
AndroidBinary androidBinary = (AndroidBinary) srcRule;
AndroidPackageableCollection packageableCollection = androidBinary.getAndroidPackageableCollection();
ImmutableSortedSet<Path> dxAbsolutePaths = resolver.getAllAbsolutePaths(packageableCollection.getNoDxClasspathEntries());
noDxJarsBuilder.addAll(dxAbsolutePaths.stream().map(projectFilesystem::relativize).iterator());
}
final Optional<Path> rJava;
if (srcRule instanceof AndroidLibrary) {
AndroidLibrary androidLibrary = (AndroidLibrary) srcRule;
BuildTarget dummyRDotJavaTarget = AndroidLibraryGraphEnhancer.getDummyRDotJavaTarget(androidLibrary.getBuildTarget());
Path src = DummyRDotJava.getRDotJavaSrcFolder(dummyRDotJavaTarget, projectFilesystem);
rJava = Optional.of(src);
} else if (srcRule instanceof AndroidResource) {
AndroidResource androidResource = (AndroidResource) srcRule;
BuildTarget dummyRDotJavaTarget = AndroidLibraryGraphEnhancer.getDummyRDotJavaTarget(androidResource.getBuildTarget());
Path src = DummyRDotJava.getRDotJavaSrcFolder(dummyRDotJavaTarget, projectFilesystem);
rJava = Optional.of(src);
} else {
rJava = Optional.empty();
}
SerializableModule module = createModuleForProjectConfig(projectConfig, rJava);
modules.add(module);
}
ImmutableSet<Path> noDxJars = noDxJarsBuilder.build();
// Update module dependencies to apply scope="PROVIDED", where appropriate.
markNoDxJarsAsProvided(projectFilesystem, modules, noDxJars, resolver);
return modules;
}
Aggregations