AndroidBinaryResourcesGraphEnhancementResult enhance()

in src/com/facebook/buck/android/AndroidBinaryResourcesGraphEnhancer.java [193:415]


  AndroidBinaryResourcesGraphEnhancementResult enhance(
      AndroidPackageableCollection packageableCollection) {

    boolean needsToFilterForLocales = !locales.isEmpty();
    // If we're using aapt2 locale filtering, then we do filtering later when we invoke aapt2,
    // so we can skip creating the resource filter tree.
    if (useAapt2LocaleFiltering) {
      if (aaptMode != AaptMode.AAPT2) {
        throw new HumanReadableException(
            "use_aapt2_locale_filtering=True is incompatible with aapt_mode=" + aaptMode);
      }
      needsToFilterForLocales = false;
    }

    boolean needsResourceFiltering =
        resourceFilter.isEnabled()
            || postFilterResourcesCmd.isPresent()
            || resourceCompressionMode.isStoreStringsAsAssets()
            || needsToFilterForLocales;

    int packageIdOffset = 0;
    ImmutableSet.Builder<SourcePath> pathToRDotTxtFiles = ImmutableSet.builder();

    ImmutableMap.Builder<APKModule, FilteredResourcesProvider> filteredResourcesProviderBuilder =
        ImmutableMap.builder();

    ImmutableAndroidBinaryResourcesGraphEnhancementResult.Builder resultBuilder =
        ImmutableAndroidBinaryResourcesGraphEnhancementResult.builder();

    List<SourcePath> apkResourceDependencyList = new ArrayList<>();

    for (APKModule module : apkModuleGraph.getAPKModules()) {
      AndroidPackageableCollection.ResourceDetails resourceDetails =
          packageableCollection.getResourceDetails().get(module);
      if (resourceDetails == null) {
        throw new RuntimeException(
            String.format("Missing resource details for module %s", module.getName()));
      }

      ImmutableSortedSet<BuildRule> resourceRules =
          getTargetsAsRules(resourceDetails.getResourcesWithNonEmptyResDir());

      ImmutableCollection<BuildRule> rulesWithResourceDirectories =
          graphBuilder.filterBuildRuleInputs(resourceDetails.getResourceDirectories());

      InternalFlavor moduleFlavor = InternalFlavor.of(module.getName());

      FilteredResourcesProvider filteredResourcesProvider;
      if (needsResourceFiltering) {
        ResourcesFilter resourcesFilter =
            createResourcesFilter(
                moduleFlavor, resourceDetails, resourceRules, rulesWithResourceDirectories);
        graphBuilder.addToIndex(resourcesFilter);
        filteredResourcesProvider = resourcesFilter;
        resourceRules = ImmutableSortedSet.of(resourcesFilter);
      } else {
        filteredResourcesProvider =
            new IdentityResourcesProvider(resourceDetails.getResourceDirectories());
      }
      filteredResourcesProviderBuilder.put(module, filteredResourcesProvider);

      AaptOutputInfo aaptOutputInfo;

      SourcePath manifestPath;
      if (module.isRootModule()) {
        manifestPath = createBaseManifestRule(packageableCollection, module);
      } else {
        if (!moduleManifestSkeleton.isPresent()) {
          continue;
        }
        AndroidManifest moduleManifestMergeRule =
            new AndroidManifest(
                buildTarget.withAppendedFlavors(MANIFEST_MERGE_FLAVOR, moduleFlavor),
                projectFilesystem,
                graphBuilder,
                moduleManifestSkeleton.get(),
                module,
                packageableCollection.getAndroidManifestPieces().get(module));
        graphBuilder.addToIndex(moduleManifestMergeRule);
        manifestPath = moduleManifestMergeRule.getSourcePathToOutput();
      }

      switch (aaptMode) {
        case AAPT1:
          {
            // Create the AaptPackageResourcesBuildable.
            AaptPackageResources aaptPackageResources =
                createAaptPackageResources(
                    buildTarget.withAppendedFlavors(AAPT_PACKAGE_FLAVOR, moduleFlavor),
                    manifestPath,
                    ImmutableList.copyOf(apkResourceDependencyList),
                    resourceDetails,
                    filteredResourcesProvider);
            graphBuilder.addToIndex(aaptPackageResources);
            aaptOutputInfo = aaptPackageResources.getAaptOutputInfo();
            apkResourceDependencyList.add(aaptOutputInfo.getPrimaryResourcesApkPath());
          }
          break;

        case AAPT2:
          {
            Aapt2Link aapt2Link =
                createAapt2Link(
                    packageIdOffset,
                    moduleFlavor,
                    manifestPath,
                    resourceDetails,
                    needsResourceFiltering
                        ? Optional.of(filteredResourcesProvider)
                        : Optional.empty(),
                    ImmutableList.copyOf(apkResourceDependencyList),
                    useProtoFormat);
            graphBuilder.addToIndex(aapt2Link);
            if (useProtoFormat) {
              // also build an ARSC flavor that we can use to as parent dependencies to other
              // modules
              Aapt2Link aapt2LinkArsc =
                  createAapt2Link(
                      packageIdOffset,
                      moduleFlavor,
                      manifestPath,
                      resourceDetails,
                      needsResourceFiltering
                          ? Optional.of(filteredResourcesProvider)
                          : Optional.empty(),
                      ImmutableList.copyOf(apkResourceDependencyList),
                      false);
              graphBuilder.addToIndex(aapt2LinkArsc);
              apkResourceDependencyList.add(
                  aapt2LinkArsc.getAaptOutputInfo().getPrimaryResourcesApkPath());
            } else {
              apkResourceDependencyList.add(
                  aapt2Link.getAaptOutputInfo().getPrimaryResourcesApkPath());
            }
            aaptOutputInfo = aapt2Link.getAaptOutputInfo();
          }
          break;

        default:
          throw new RuntimeException("Unexpected aaptMode: " + aaptMode);
      }

      if (module.isRootModule()) {
        Optional<PackageStringAssets> packageStringAssets = Optional.empty();
        if (resourceCompressionMode.isStoreStringsAsAssets()) {
          // TODO(cjhopman): we should be able to support this in exo-for-resources
          if (exopackageForResources) {
            throw new HumanReadableException(
                "exopackage_modes and resource_compression_mode for android_binary %s are "
                    + "incompatible. Either remove %s from exopackage_modes or disable storing strings "
                    + "as assets.",
                buildTarget, ExopackageMode.RESOURCES);
          }
          packageStringAssets =
              Optional.of(
                  createPackageStringAssets(
                      resourceRules,
                      rulesWithResourceDirectories,
                      filteredResourcesProvider,
                      aaptOutputInfo));
          graphBuilder.addToIndex(packageStringAssets.get());
        }

        resultBuilder.setPackageStringAssets(packageStringAssets);

        createMergeAndExoResources(
            packageableCollection,
            pathToRDotTxtFiles,
            resultBuilder,
            aaptOutputInfo,
            packageStringAssets);

        // Create a rule that copies the AndroidManifest. This allows the AndroidBinary rule (and
        // exopackage installation rules) to have a runtime dep on the manifest without having to
        // have a runtime dep on the full aapt output.
        ExportFile manifestCopyRule =
            new ExportFile(
                originalBuildTarget.withAppendedFlavors(COPY_MANIFEST_FLAVOR),
                projectFilesystem,
                graphBuilder,
                "AndroidManifest.xml",
                ExportFileDescription.Mode.COPY,
                aaptOutputInfo.getAndroidManifestXml(),
                ExportFileDirectoryAction.FAIL);
        graphBuilder.addToIndex(manifestCopyRule);
        resultBuilder.setAndroidManifestXml(manifestCopyRule.getSourcePathToOutput());
      } else {
        resultBuilder.putModuleResourceApkPaths(
            module, aaptOutputInfo.getPrimaryResourcesApkPath());
      }
      resultBuilder.addAaptGeneratedProguardConfigFiles(
          aaptOutputInfo.getAaptGeneratedProguardConfigFile());
      pathToRDotTxtFiles.add(aaptOutputInfo.getPathToRDotTxt());
      packageIdOffset++;
    }

    Optional<GenerateRDotJava> generateRDotJava = Optional.empty();
    ImmutableMap<APKModule, FilteredResourcesProvider> allFilteredResourceProviders =
        filteredResourcesProviderBuilder.build();
    if (allFilteredResourceProviders.values().stream().anyMatch(f -> f.hasResources())) {
      generateRDotJava =
          Optional.of(
              createGenerateRDotJava(
                  pathToRDotTxtFiles.build(),
                  getTargetsAsRules(
                      packageableCollection.getResourceDetails().values().stream()
                          .flatMap(r -> r.getResourcesWithNonEmptyResDir().stream())
                          .collect(ImmutableList.toImmutableList())),
                  allFilteredResourceProviders.values()));

      graphBuilder.addToIndex(generateRDotJava.get());

      if (shouldBuildStringSourceMap) {
        graphBuilder.addToIndex(
            createGenerateStringResources(allFilteredResourceProviders.values().asList()));
      }
    }

    return resultBuilder
        .setRDotJavaDir(
            generateRDotJava.map(GenerateRDotJava::getSourcePathToGeneratedRDotJavaSrcFiles))
        .build();
  }