/**
  * The only dep for this rule should be {@link #javaLibrary}. Therefore, the ABI key for the deps
  * of this buildable is the hash of the {@code .class} files for {@link #javaLibrary}.
  */
 @Override
 public Sha1HashCode getAbiKeyForDeps(DefaultRuleKeyBuilderFactory defaultRuleKeyBuilderFactory) {
   return computeAbiKey(javaLibrary.getClassNamesToHashes());
 }
  @Override
  public ImmutableList<Step> getBuildSteps(
      BuildContext context, final BuildableContext buildableContext) {
    ImmutableList.Builder<Step> steps = ImmutableList.builder();

    steps.add(new RmStep(getProjectFilesystem(), getPathToDex(), /* shouldForceDeletion */ true));

    // Make sure that the buck-out/gen/ directory exists for this.buildTarget.
    steps.add(new MkdirStep(getProjectFilesystem(), getPathToDex().getParent()));

    // If there are classes, run dx.
    final ImmutableSortedMap<String, HashCode> classNamesToHashes =
        javaLibrary.getClassNamesToHashes();
    final boolean hasClassesToDx = !classNamesToHashes.isEmpty();
    final Supplier<Integer> linearAllocEstimate;
    if (hasClassesToDx) {
      Path pathToOutputFile = javaLibrary.getPathToOutput();
      EstimateLinearAllocStep estimate =
          new EstimateLinearAllocStep(getProjectFilesystem(), pathToOutputFile);
      steps.add(estimate);
      linearAllocEstimate = estimate;

      // To be conservative, use --force-jumbo for these intermediate .dex files so that they can be
      // merged into a final classes.dex that uses jumbo instructions.
      DxStep dx =
          new DxStep(
              getProjectFilesystem(),
              getPathToDex(),
              Collections.singleton(pathToOutputFile),
              EnumSet.of(
                  DxStep.Option.USE_CUSTOM_DX_IF_AVAILABLE,
                  DxStep.Option.RUN_IN_PROCESS,
                  DxStep.Option.NO_OPTIMIZE,
                  DxStep.Option.FORCE_JUMBO));
      steps.add(dx);

      // The `DxStep` delegates to android tools to build a ZIP with timestamps in it, making
      // the output non-deterministic.  So use an additional scrubbing step to zero these out.
      steps.add(new ZipScrubberStep(getProjectFilesystem(), getPathToDex()));

    } else {
      linearAllocEstimate = Suppliers.ofInstance(0);
    }

    // Run a step to record artifacts and metadata. The values recorded depend upon whether dx was
    // run.
    String stepName = hasClassesToDx ? "record_dx_success" : "record_empty_dx";
    AbstractExecutionStep recordArtifactAndMetadataStep =
        new AbstractExecutionStep(stepName) {
          @Override
          public StepExecutionResult execute(ExecutionContext context) throws IOException {
            if (hasClassesToDx) {
              buildableContext.recordArtifact(getPathToDex());
            }

            buildableContext.addMetadata(
                LINEAR_ALLOC_KEY_ON_DISK_METADATA, String.valueOf(linearAllocEstimate.get()));

            // Record the classnames to hashes map.
            buildableContext.addMetadata(
                CLASSNAMES_TO_HASHES,
                context
                    .getObjectMapper()
                    .writeValueAsString(
                        Maps.transformValues(classNamesToHashes, Functions.toStringFunction())));

            return StepExecutionResult.SUCCESS;
          }
        };
    steps.add(recordArtifactAndMetadataStep);

    return steps.build();
  }