NestedSet<? extends Artifact> dependentLinkedBinaries() {
      if (ruleContext.attributes().getAttributeDefinition("binary") == null) {
        return NestedSetBuilder.emptySet(Order.STABLE_ORDER);
      }

      NestedSetBuilder<Artifact> linkedBinaries = NestedSetBuilder.stableOrder();
      for (ObjcProvider provider :
          ruleContext.getPrerequisites("binary", Mode.DONT_CHECK, ObjcProvider.class)) {
        linkedBinaries.addTransitive(provider.get(ObjcProvider.LINKED_BINARY));
      }

      return linkedBinaries.build();
    }
  /** Registers an action to copy Swift standard library dylibs into app bundle. */
  private void registerSwiftStdlibActionsIfNecessary() {
    if (!objcProvider.is(USES_SWIFT)) {
      return;
    }

    ObjcConfiguration objcConfiguration = ObjcRuleClasses.objcConfiguration(ruleContext);

    CustomCommandLine.Builder commandLine =
        CustomCommandLine.builder()
            .addPath(intermediateArtifacts.swiftFrameworksFileZip().getExecPath())
            .add("--platform")
            .add(IosSdkCommands.swiftPlatform(objcConfiguration))
            .addExecPath("--scan-executable", intermediateArtifacts.combinedArchitectureBinary());

    ruleContext.registerAction(
        ObjcRuleClasses.spawnOnDarwinActionBuilder(ruleContext)
            .setMnemonic("SwiftStdlibCopy")
            .setExecutable(attributes.swiftStdlibToolWrapper())
            .setCommandLine(commandLine.build())
            .addOutput(intermediateArtifacts.swiftFrameworksFileZip())
            .addInput(intermediateArtifacts.combinedArchitectureBinary())
            // TODO(dmaclach): Adding realpath and xcrunwrapper should not be required once
            // https://github.com/google/bazel/issues/285 is fixed.
            .addInput(attributes.realpath())
            .addInput(CompilationSupport.xcrunwrapper(ruleContext).getExecutable())
            .build(ruleContext));
  }
  /**
   * Adds any files to the given nested set builder that should be built if this application is the
   * top level target in a blaze invocation.
   *
   * @return this application support
   * @throws InterruptedException
   */
  ReleaseBundlingSupport addFilesToBuild(NestedSetBuilder<Artifact> filesToBuild)
      throws InterruptedException {
    NestedSetBuilder<Artifact> debugSymbolBuilder =
        NestedSetBuilder.<Artifact>stableOrder()
            .addTransitive(objcProvider.get(ObjcProvider.DEBUG_SYMBOLS));

    for (Artifact breakpadFile : getBreakpadFiles().values()) {
      filesToBuild.add(breakpadFile);
    }

    if (linkedBinary == LinkedBinary.LOCAL_AND_DEPENDENCIES
        && ObjcRuleClasses.objcConfiguration(ruleContext).generateDebugSymbols()) {
      IntermediateArtifacts intermediateArtifacts =
          ObjcRuleClasses.intermediateArtifacts(ruleContext);
      debugSymbolBuilder
          .add(intermediateArtifacts.dsymPlist())
          .add(intermediateArtifacts.dsymSymbol())
          .add(intermediateArtifacts.breakpadSym());
    }

    filesToBuild
        .add(ruleContext.getImplicitOutputArtifact(ReleaseBundlingSupport.IPA))
        // TODO(bazel-team): Fat binaries may require some merging of these file rather than just
        // making them available.
        .addTransitive(debugSymbolBuilder.build());
    return this;
  }
 ImmutableMap<String, Artifact> cpuSpecificBreakpadFiles() {
   ImmutableMap.Builder<String, Artifact> results = ImmutableMap.builder();
   if (ruleContext.attributes().has("binary", BuildType.LABEL)) {
     for (TransitiveInfoCollection prerequisite :
         ruleContext.getPrerequisites("binary", Mode.DONT_CHECK)) {
       ObjcProvider prerequisiteProvider = prerequisite.getProvider(ObjcProvider.class);
       if (prerequisiteProvider != null) {
         Artifact sourceBreakpad =
             Iterables.getOnlyElement(
                 prerequisiteProvider.get(ObjcProvider.BREAKPAD_FILE), null);
         if (sourceBreakpad != null) {
           String cpu =
               prerequisite.getConfiguration().getFragment(ObjcConfiguration.class).getIosCpu();
           results.put(cpu, sourceBreakpad);
         }
       }
     }
   }
   return results.build();
 }
  private ReleaseBundlingSupport registerSignBundleAction(
      Artifact entitlements, Artifact ipaOutput, Artifact ipaUnsigned) {
    // TODO(bazel-team): Support variable substitution

    ImmutableList.Builder<String> dirsToSign = new ImmutableList.Builder<>();

    // Explicitly sign Swift dylibs. Unfortunately --deep option on codesign doesn't do this
    // automatically.
    // The order here is important. The innermost code must singed first.
    String bundleDir = ShellUtils.shellEscape(bundling.getBundleDir());
    if (objcProvider.is(USES_SWIFT)) {
      dirsToSign.add(bundleDir + "/Frameworks/*");
    }
    dirsToSign.add(bundleDir);

    StringBuilder codesignCommandLineBuilder = new StringBuilder();
    for (String dir : dirsToSign.build()) {
      codesignCommandLineBuilder
          .append(codesignCommand(entitlements, "${t}/" + dir))
          .append(" && ");
    }

    // TODO(bazel-team): Support nested code signing.
    String shellCommand =
        "set -e && "
            + "t=$(mktemp -d -t signing_intermediate) && "
            + "trap \"rm -rf ${t}\" EXIT && "
            // Get an absolute path since we need to cd into the temp directory for zip.
            + "signed_ipa=${PWD}/"
            + ipaOutput.getShellEscapedExecPathString()
            + " && "
            + "/usr/bin/unzip -qq "
            + ipaUnsigned.getShellEscapedExecPathString()
            + " -d ${t} && "
            + codesignCommandLineBuilder.toString()
            // Using zip since we need to preserve permissions
            + "cd ${t} && /usr/bin/zip -q -r \"${signed_ipa}\" .";
    ruleContext.registerAction(
        ObjcRuleClasses.spawnBashOnDarwinActionBuilder(ruleContext, shellCommand)
            .setMnemonic("IosSignBundle")
            .setProgressMessage("Signing iOS bundle: " + ruleContext.getLabel())
            .addInput(ipaUnsigned)
            .addInput(attributes.provisioningProfile())
            .addInput(entitlements)
            .addOutput(ipaOutput)
            .build(ruleContext));

    return this;
  }
  /**
   * Validates application-related attributes set on this rule and registers any errors with the
   * rule context.
   *
   * @return this application support
   */
  ReleaseBundlingSupport validateAttributes() {
    // No asset catalogs. That means you cannot specify app_icon or
    // launch_image attributes, since they must not exist. However, we don't
    // run actool in this case, which means it does not do validity checks,
    // and we MUST raise our own error somehow...
    if (!objcProvider.hasAssetCatalogs()) {
      if (attributes.appIcon() != null) {
        ruleContext.attributeError(
            "app_icon", String.format(NO_ASSET_CATALOG_ERROR_FORMAT, attributes.appIcon()));
      }
      if (attributes.launchImage() != null) {
        ruleContext.attributeError(
            "launch_image", String.format(NO_ASSET_CATALOG_ERROR_FORMAT, attributes.launchImage()));
      }
    }

    if (bundleSupport.targetDeviceFamilies().isEmpty()) {
      ruleContext.attributeError("families", INVALID_FAMILIES_ERROR);
    }

    return this;
  }