Exemple #1
0
  @Override
  public ImmutableList<Step> getBuildSteps(
      BuildContext context, BuildableContext buildableContext) {
    ImmutableList.Builder<Step> stepsBuilder = ImmutableList.builder();

    Path metadataPath = getMetadataPath();

    Path infoPlistInputPath = getResolver().getPath(infoPlist);
    Path infoPlistSubstitutionTempPath = BuildTargets.getScratchPath(getBuildTarget(), "%s.plist");
    Path infoPlistOutputPath = metadataPath.resolve("Info.plist");

    stepsBuilder.add(
        new MakeCleanDirectoryStep(bundleRoot),
        new MkdirStep(metadataPath),
        // TODO(user): This is only appropriate for .app bundles.
        new WriteFileStep("APPLWRUN", metadataPath.resolve("PkgInfo"), /* executable */ false),
        new FindAndReplaceStep(
            infoPlistInputPath,
            infoPlistSubstitutionTempPath,
            InfoPlistSubstitution.createVariableExpansionFunction(
                withDefaults(
                    infoPlistSubstitutions,
                    ImmutableMap.of(
                        "EXECUTABLE_NAME", binaryName,
                        "PRODUCT_NAME", binaryName)))),
        new PlistProcessStep(
            infoPlistSubstitutionTempPath,
            infoPlistOutputPath,
            getInfoPlistAdditionalKeys(platformName, sdkName),
            getInfoPlistOverrideKeys(platformName),
            PlistProcessStep.OutputFormat.BINARY));

    if (binary.isPresent() && binary.get().getPathToOutput() != null) {
      stepsBuilder.add(new MkdirStep(bundleRoot.resolve(this.destinations.getExecutablesPath())));
      Path bundleBinaryPath = bundleRoot.resolve(binaryPath);
      stepsBuilder.add(CopyStep.forFile(binary.get().getPathToOutput(), bundleBinaryPath));
      stepsBuilder.add(
          new DsymStep(
              dsymutil.getCommandPrefix(getResolver()),
              bundleBinaryPath,
              bundleBinaryPath.resolveSibling(
                  bundleBinaryPath.getFileName().toString() + ".dSYM")));
      stepsBuilder.add(
          new DefaultShellStep(
              ImmutableList.<String>builder()
                  .addAll(strip.getCommandPrefix(getResolver()))
                  .add("-S")
                  .add(getProjectFilesystem().resolve(bundleBinaryPath).toString())
                  .build()));
    }

    Path bundleDestinationPath = bundleRoot.resolve(this.destinations.getResourcesPath());
    for (SourcePath dir : resourceDirs) {
      stepsBuilder.add(new MkdirStep(bundleDestinationPath));
      stepsBuilder.add(
          CopyStep.forDirectory(
              getResolver().getPath(dir),
              bundleDestinationPath,
              CopyStep.DirectoryMode.DIRECTORY_AND_CONTENTS));
    }
    for (SourcePath dir : dirsContainingResourceDirs) {
      stepsBuilder.add(new MkdirStep(bundleDestinationPath));
      stepsBuilder.add(
          CopyStep.forDirectory(
              getResolver().getPath(dir),
              bundleDestinationPath,
              CopyStep.DirectoryMode.CONTENTS_ONLY));
    }
    for (SourcePath file : resourceFiles) {
      stepsBuilder.add(new MkdirStep(bundleDestinationPath));
      Path resolvedFilePath = getResolver().getPath(file);
      Path destinationPath = bundleDestinationPath.resolve(resolvedFilePath.getFileName());
      addResourceProcessingSteps(resolvedFilePath, destinationPath, stepsBuilder);
    }

    addStepsToCopyExtensionBundlesDependencies(stepsBuilder);

    if (resourceVariantFiles.isPresent()) {
      for (SourcePath variantSourcePath : resourceVariantFiles.get()) {
        Path variantFilePath = getResolver().getPath(variantSourcePath);

        Path variantDirectory = variantFilePath.getParent();
        if (variantDirectory == null || !variantDirectory.toString().endsWith(".lproj")) {
          throw new HumanReadableException(
              "Variant files have to be in a directory with name ending in '.lproj', "
                  + "but '%s' is not.",
              variantFilePath);
        }

        Path bundleVariantDestinationPath =
            bundleDestinationPath.resolve(variantDirectory.getFileName());
        stepsBuilder.add(new MkdirStep(bundleVariantDestinationPath));

        Path destinationPath = bundleVariantDestinationPath.resolve(variantFilePath.getFileName());
        addResourceProcessingSteps(variantFilePath, destinationPath, stepsBuilder);
      }
    }

    if (assetCatalog.isPresent()) {
      Path bundleDir = assetCatalog.get().getOutputDir();
      stepsBuilder.add(
          CopyStep.forDirectory(bundleDir, bundleRoot, CopyStep.DirectoryMode.CONTENTS_ONLY));
    }

    // Copy the .mobileprovision file if the platform requires it.
    if (provisioningProfiles.isPresent()) {
      Optional<Path> entitlementsPlist = Optional.absent();
      final String srcRoot =
          context.getProjectRoot().resolve(getBuildTarget().getBasePath()).toString();
      Optional<String> entitlementsPlistString =
          InfoPlistSubstitution.getVariableExpansionForPlatform(
              CODE_SIGN_ENTITLEMENTS,
              platformName,
              withDefaults(
                  infoPlistSubstitutions,
                  ImmutableMap.of(
                      "SOURCE_ROOT", srcRoot,
                      "SRCROOT", srcRoot)));
      if (entitlementsPlistString.isPresent()) {
        entitlementsPlist = Optional.of(Paths.get(entitlementsPlistString.get()));
      }

      final Path signingEntitlementsTempPath =
          BuildTargets.getScratchPath(getBuildTarget(), "%s.xcent");

      stepsBuilder.add(
          new ProvisioningProfileCopyStep(
              infoPlistOutputPath,
              Optional.<String>absent(), // Provisioning profile UUID -- find automatically.
              entitlementsPlist,
              provisioningProfiles.get(),
              bundleDestinationPath.resolve("embedded.mobileprovision"),
              signingEntitlementsTempPath));

      stepsBuilder.add(
          new CodeSignStep(
              bundleDestinationPath,
              signingEntitlementsTempPath,
              codeSignIdentity.get().getHash()));
    }

    // Ensure the bundle directory is archived so we can fetch it later.
    buildableContext.recordArtifact(getPathToOutput());

    return stepsBuilder.build();
  }
Exemple #2
0
  AppleBundle(
      BuildRuleParams params,
      SourcePathResolver resolver,
      Either<AppleBundleExtension, String> extension,
      SourcePath infoPlist,
      Map<String, String> infoPlistSubstitutions,
      Optional<BuildRule> binary,
      AppleBundleDestinations destinations,
      Set<SourcePath> resourceDirs,
      Set<SourcePath> resourceFiles,
      Set<SourcePath> dirsContainingResourceDirs,
      ImmutableSet<SourcePath> extensionBundlePaths,
      Optional<ImmutableSet<SourcePath>> resourceVariantFiles,
      Tool ibtool,
      Tool dsymutil,
      Tool strip,
      Optional<AppleAssetCatalog> assetCatalog,
      Set<BuildTarget> tests,
      AppleSdk sdk,
      ImmutableSet<CodeSignIdentity> allValidCodeSignIdentities,
      Optional<SourcePath> provisioningProfileSearchPath) {
    super(params, resolver);
    this.extension =
        extension.isLeft() ? extension.getLeft().toFileExtension() : extension.getRight();
    this.infoPlist = infoPlist;
    this.infoPlistSubstitutions = ImmutableMap.copyOf(infoPlistSubstitutions);
    this.binary = binary;
    this.destinations = destinations;
    this.resourceDirs = resourceDirs;
    this.resourceFiles = resourceFiles;
    this.dirsContainingResourceDirs = dirsContainingResourceDirs;
    this.extensionBundlePaths = extensionBundlePaths;
    this.resourceVariantFiles = resourceVariantFiles;
    this.ibtool = ibtool;
    this.dsymutil = dsymutil;
    this.strip = strip;
    this.assetCatalog = assetCatalog;
    this.binaryName = getBinaryName(getBuildTarget());
    this.bundleRoot = getBundleRoot(getBuildTarget(), this.extension);
    this.binaryPath = this.destinations.getExecutablesPath().resolve(this.binaryName);
    this.tests = ImmutableSortedSet.copyOf(tests);
    this.platformName = sdk.getApplePlatform().getName();
    this.sdkName = sdk.getName();

    // We need to resolve the possible set of profiles and code sign identity at construction time
    // because they form part of the rule key.
    if (binary.isPresent() && ApplePlatform.needsCodeSign(this.platformName)) {
      final Path searchPath;
      if (provisioningProfileSearchPath.isPresent()) {
        searchPath = resolver.getResolvedPath(provisioningProfileSearchPath.get());
      } else {
        searchPath =
            Paths.get(
                System.getProperty("user.home") + "/Library/MobileDevice/Provisioning Profiles");
      }

      Optional<ImmutableSet<ProvisioningProfileMetadata>> provisioningProfiles;
      try {
        provisioningProfiles =
            Optional.of(ProvisioningProfileCopyStep.findProfilesInPath(searchPath));
      } catch (InterruptedException e) {
        // We get here if the user pressed Ctrl-C during the profile discovery step.
        // In this case, we'll fail anyway since the set of profiles will be empty.
        provisioningProfiles = Optional.of(ImmutableSet.<ProvisioningProfileMetadata>of());
      }
      this.provisioningProfiles = provisioningProfiles;

      Optional<CodeSignIdentity> foundIdentity = Optional.absent();
      Optional<String> customIdentity =
          InfoPlistSubstitution.getVariableExpansionForPlatform(
              CODE_SIGN_IDENTITY, this.platformName, this.infoPlistSubstitutions);
      if (customIdentity.isPresent()) {
        LOG.debug("Bundle specifies custom code signing identity: " + customIdentity.get());
        if (CodeSignIdentity.isHash(customIdentity.get())) {
          for (CodeSignIdentity identity : allValidCodeSignIdentities) {
            if (identity.getHash().equals(customIdentity.get())) {
              foundIdentity = Optional.of(identity);
              break;
            }
          }
        } else {
          for (CodeSignIdentity identity : allValidCodeSignIdentities) {
            if (identity.getFullName().startsWith(customIdentity.get())) {
              foundIdentity = Optional.of(identity);
              break;
            }
          }
        }
      } else if (!allValidCodeSignIdentities.isEmpty()) {
        LOG.debug("Using default code signing identity");
        Iterator<CodeSignIdentity> it = allValidCodeSignIdentities.iterator();
        foundIdentity = Optional.of(it.next());
      }
      if (!foundIdentity.isPresent()) {
        throw new HumanReadableException(
            "The platform "
                + platformName
                + " for this target "
                + "requires code signing but couldn't find a compatible code signing identity to use.");
      }
      LOG.debug("Code signing identity is " + foundIdentity.toString());
      this.codeSignIdentity = foundIdentity;
    } else {
      this.provisioningProfiles = Optional.absent();
      this.codeSignIdentity = Optional.absent();
    }
  }