/**
   * Creates/finds the set of build rules that correspond to pre-dex'd artifacts that should be
   * merged to create the final classes.dex for the APK.
   *
   * <p>This method may modify {@code ruleResolver}, inserting new rules into its index.
   */
  @VisibleForTesting
  BuildRule createPreDexMergeRule(UberRDotJava uberRDotJava) {
    ImmutableSet.Builder<DexProducedFromJavaLibrary> preDexDeps = ImmutableSet.builder();
    ImmutableSet<JavaLibrary> transitiveJavaDeps =
        Classpaths.getClasspathEntries(originalDeps).keySet();
    for (JavaLibrary javaLibrary : transitiveJavaDeps) {
      // If the rule has no output file (which happens when a java_library has no srcs or
      // resources, but export_deps is true), then there will not be anything to dx.
      if (javaLibrary.getPathToOutputFile() == null) {
        continue;
      }

      // If the rule is in the no_dx list, then do not pre-dex it.
      if (buildRulesToExcludeFromDex.contains(javaLibrary.getBuildTarget())) {
        continue;
      }

      // See whether the corresponding IntermediateDexRule has already been added to the
      // ruleResolver.
      BuildTarget originalTarget = javaLibrary.getBuildTarget();
      BuildTarget preDexTarget =
          new BuildTarget(originalTarget.getBaseName(), originalTarget.getShortName(), DEX_FLAVOR);
      BuildRule preDexRule = ruleResolver.get(preDexTarget);
      if (preDexRule != null) {
        preDexDeps.add((DexProducedFromJavaLibrary) preDexRule.getBuildable());
        continue;
      }

      // Create the IntermediateDexRule and add it to both the ruleResolver and preDexDeps.
      DexProducedFromJavaLibrary preDex = new DexProducedFromJavaLibrary(preDexTarget, javaLibrary);
      buildRuleAndAddToIndex(
          preDex,
          BuildRuleType.PRE_DEX,
          preDexTarget,
          ImmutableSortedSet.of(ruleResolver.get(javaLibrary.getBuildTarget())));
      preDexDeps.add(preDex);
    }

    ImmutableSet<DexProducedFromJavaLibrary> allPreDexDeps = preDexDeps.build();

    BuildTarget buildTargetForDexMerge = createBuildTargetWithFlavor(DEX_MERGE_FLAVOR);
    PreDexMerge preDexMerge =
        new PreDexMerge(
            buildTargetForDexMerge, primaryDexPath, dexSplitMode, allPreDexDeps, uberRDotJava);
    BuildRule preDexMergeBuildRule =
        buildRuleAndAddToIndex(
            preDexMerge,
            BuildRuleType.DEX_MERGE,
            buildTargetForDexMerge,
            getDexMergeDeps(uberRDotJava, allPreDexDeps));

    return preDexMergeBuildRule;
  }
Пример #2
0
 @Override
 public ImmutableSortedSet<BuildRule> getEnhancedDeps(BuildRuleResolver ruleResolver) {
   SourcePath skeletonFile = getSkeletonFile();
   if (skeletonFile instanceof BuildTargetSourcePath) {
     BuildTarget skeletonTarget = ((BuildTargetSourcePath) skeletonFile).getTarget();
     BuildRule skeletonRule = ruleResolver.get(skeletonTarget);
     return ImmutableSortedSet.<BuildRule>of(skeletonRule);
   } else {
     return ImmutableSortedSet.<BuildRule>of();
   }
 }
    @Override
    public AndroidInstrumentationApk build(BuildRuleResolver ruleResolver) {
      BuildRule apkRule = ruleResolver.get(this.apk);
      if (apkRule == null) {
        throw new HumanReadableException("Must specify apk for " + getBuildTarget());
      } else if (!(apkRule instanceof InstallableBuildRule)) {
        throw new HumanReadableException(
            "In %s, apk='%s' must be an android_binary() or apk_genrule() but was %s().",
            getBuildTarget(), apkRule.getFullyQualifiedName(), apkRule.getType().getName());
      }

      AndroidBinaryRule underlyingApk = getUnderlyingApk((InstallableBuildRule) apkRule);

      return new AndroidInstrumentationApk(
          createBuildRuleParams(ruleResolver), manifest, underlyingApk);
    }
Пример #4
0
  /**
   * Tests an android_binary with multiple dependent android_library rules, each with its own assets
   * directory.
   */
  @Test
  public void testCreateAllAssetsDirectoryWithMultipleAssetsDirectories() throws IOException {
    BuildRuleResolver ruleResolver = new BuildRuleResolver();

    // Two android_library deps, each with an assets directory.
    JavaLibraryRule libraryOne =
        createAndroidLibraryRule(
            "//java/src/com/facebook/base:libraryOne",
            ruleResolver,
            null, /* resDirectory */
            "java/src/com/facebook/base/assets1",
            null /* nativeLibsDirectory */);
    JavaLibraryRule libraryTwo =
        createAndroidLibraryRule(
            "//java/src/com/facebook/base:libraryTwo",
            ruleResolver,
            null, /* resDirectory */
            "java/src/com/facebook/base/assets2",
            null /* nativeLibsDirectory */);

    // One android_binary rule that depends on the two android_library rules.
    BuildTarget binaryBuildTarget =
        BuildTargetFactory.newInstance("//java/src/com/facebook/base:apk");
    AndroidBinaryRule androidBinary =
        ruleResolver.buildAndAddToIndex(
            AndroidBinaryRule.newAndroidBinaryRuleBuilder(new FakeAbstractBuildRuleBuilderParams())
                .setBuildTarget(binaryBuildTarget)
                .addClasspathDep(libraryOne.getBuildTarget())
                .addClasspathDep(libraryTwo.getBuildTarget())
                .setManifest("java/src/com/facebook/base/AndroidManifest.xml")
                .setTarget("Google Inc.:Google APIs:16")
                .setKeystore(addKeystoreRule(ruleResolver))
                .setPackageType("debug"));

    AndroidResourceRule resourceOne =
        (AndroidResourceRule)
            ruleResolver.get(
                BuildTargetFactory.newInstance(
                    "//java/src/com/facebook/base:libraryOne_resources"));
    AndroidResourceRule resourceTwo =
        (AndroidResourceRule)
            ruleResolver.get(
                BuildTargetFactory.newInstance(
                    "//java/src/com/facebook/base:libraryTwo_resources"));

    // Build up the parameters needed to invoke createAllAssetsDirectory().
    Set<String> assetsDirectories =
        ImmutableSet.of(resourceOne.getAssets(), resourceTwo.getAssets());
    ImmutableList.Builder<Step> commands = ImmutableList.builder();
    DirectoryTraverser traverser =
        new DirectoryTraverser() {
          @Override
          public void traverse(DirectoryTraversal traversal) throws IOException {
            String rootPath = Paths.normalizePathSeparator(traversal.getRoot().getPath());
            if ("java/src/com/facebook/base/assets1".equals(rootPath)) {
              traversal.visit(
                  new File("java/src/com/facebook/base/assets1", "guava-10.0.1-fork.dex.1.jar"),
                  "guava-10.0.1-fork.dex.1.jar");
            } else if ("java/src/com/facebook/base/assets2".equals(rootPath)) {
              traversal.visit(
                  new File("java/src/com/facebook/base/assets2", "fonts/Theinhardt-Medium.otf"),
                  "fonts/Theinhardt-Medium.otf");
              traversal.visit(
                  new File("java/src/com/facebook/base/assets2", "fonts/Theinhardt-Regular.otf"),
                  "fonts/Theinhardt-Regular.otf");
            } else {
              throw new RuntimeException("Unexpected path: " + rootPath);
            }
          }
        };

    // Invoke createAllAssetsDirectory(), the method under test.
    Optional<String> allAssetsDirectory =
        androidBinary.createAllAssetsDirectory(
            assetsDirectories, ImmutableMap.<String, File>of(), commands, traverser);

    // Verify that an assets/ directory will be created and passed to aapt.
    assertTrue(allAssetsDirectory.isPresent());
    assertEquals(BIN_DIR + "/java/src/com/facebook/base/__assets_apk__", allAssetsDirectory.get());
    List<? extends Step> expectedCommands =
        ImmutableList.of(
            new MakeCleanDirectoryStep(BIN_DIR + "/java/src/com/facebook/base/__assets_apk__"),
            new MkdirAndSymlinkFileStep(
                "java/src/com/facebook/base/assets1/guava-10.0.1-fork.dex.1.jar",
                BIN_DIR + "/java/src/com/facebook/base/__assets_apk__/guava-10.0.1-fork.dex.1.jar"),
            new MkdirAndSymlinkFileStep(
                "java/src/com/facebook/base/assets2/fonts/Theinhardt-Medium.otf",
                BIN_DIR + "/java/src/com/facebook/base/__assets_apk__/fonts/Theinhardt-Medium.otf"),
            new MkdirAndSymlinkFileStep(
                "java/src/com/facebook/base/assets2/fonts/Theinhardt-Regular.otf",
                BIN_DIR
                    + "/java/src/com/facebook/base/__assets_apk__/fonts/Theinhardt-Regular.otf"));
    MoreAsserts.assertListEquals(expectedCommands, commands.build());
  }
Пример #5
0
  /**
   * Tests an android_binary with one dependent android_library rule that contains an assets
   * directory.
   */
  @Test
  public void testCreateAllAssetsDirectoryWithOneAssetsDirectory() throws IOException {
    BuildRuleResolver ruleResolver = new BuildRuleResolver();

    // Two android_library deps, one of which has an assets directory.
    JavaLibraryRule libraryOne =
        createAndroidLibraryRule(
            "//java/src/com/facebook/base:libraryOne",
            ruleResolver,
            null, /* resDirectory */
            null, /* assetDirectory */
            null /* nativeLibsDirectory */);
    JavaLibraryRule libraryTwo =
        createAndroidLibraryRule(
            "//java/src/com/facebook/base:libraryTwo",
            ruleResolver,
            null, /* resDirectory */
            "java/src/com/facebook/base/assets2",
            null /* nativeLibsDirectory */);

    AndroidResourceRule resourceOne =
        (AndroidResourceRule)
            ruleResolver.get(
                BuildTargetFactory.newInstance(
                    "//java/src/com/facebook/base:libraryTwo_resources"));

    // One android_binary rule that depends on the two android_library rules.
    BuildTarget binaryBuildTarget =
        BuildTargetFactory.newInstance("//java/src/com/facebook/base:apk");
    AndroidBinaryRule androidBinary =
        ruleResolver.buildAndAddToIndex(
            AndroidBinaryRule.newAndroidBinaryRuleBuilder(new FakeAbstractBuildRuleBuilderParams())
                .setBuildTarget(binaryBuildTarget)
                .addClasspathDep(libraryOne.getBuildTarget())
                .addClasspathDep(libraryTwo.getBuildTarget())
                .setManifest("java/src/com/facebook/base/AndroidManifest.xml")
                .setTarget("Google Inc.:Google APIs:16")
                .setKeystore(addKeystoreRule(ruleResolver))
                .setPackageType("debug"));

    // Build up the parameters needed to invoke createAllAssetsDirectory().
    Set<String> assetsDirectories = ImmutableSet.of(resourceOne.getAssets());
    ImmutableList.Builder<Step> commands = ImmutableList.builder();
    DirectoryTraverser traverser =
        new DirectoryTraverser() {
          @Override
          public void traverse(DirectoryTraversal traversal) throws IOException {
            String rootPath = Paths.normalizePathSeparator(traversal.getRoot().getPath());
            if ("java/src/com/facebook/base/assets2".equals(rootPath)) {
              traversal.visit(
                  new File("java/src/com/facebook/base/assets2", "fonts/Theinhardt-Medium.otf"),
                  "fonts/Theinhardt-Medium.otf");
              traversal.visit(
                  new File("java/src/com/facebook/base/assets2", "fonts/Theinhardt-Regular.otf"),
                  "fonts/Theinhardt-Regular.otf");
            } else {
              throw new RuntimeException("Unexpected path: " + rootPath);
            }
          }
        };

    // Invoke createAllAssetsDirectory(), the method under test.
    Optional<String> allAssetsDirectory =
        androidBinary.createAllAssetsDirectory(
            assetsDirectories, ImmutableMap.<String, File>of(), commands, traverser);

    // Verify that the existing assets/ directory will be passed to aapt.
    assertTrue(allAssetsDirectory.isPresent());
    assertEquals(
        "Even though there is only one assets directory, the one in "
            + BIN_DIR
            + " should be used.",
        androidBinary.getPathToAllAssetsDirectory(),
        allAssetsDirectory.get());
  }