/**
   * Registers actions required to build an application. This includes any {@link
   * BundleSupport#registerActions(ObjcProvider) bundle} and bundle merge actions, signing this
   * application if appropriate and combining several single-architecture binaries into one
   * multi-architecture binary.
   *
   * @return this application support
   * @throws InterruptedException
   */
  ReleaseBundlingSupport registerActions() throws InterruptedException {
    bundleSupport.registerActions(objcProvider);

    registerCombineArchitecturesAction();
    registerTransformAndCopyBreakpadFilesAction();
    registerSwiftStdlibActionsIfNecessary();

    AppleConfiguration appleConfiguration = ruleContext.getFragment(AppleConfiguration.class);
    Artifact ipaOutput = ruleContext.getImplicitOutputArtifact(IPA);

    Artifact maybeSignedIpa;
    if (appleConfiguration.getBundlingPlatform() == Platform.IOS_SIMULATOR) {
      maybeSignedIpa = ipaOutput;
    } else if (attributes.provisioningProfile() == null) {
      throw new IllegalStateException(DEVICE_NO_PROVISIONING_PROFILE);
    } else {
      maybeSignedIpa = registerBundleSigningActions(ipaOutput);
    }

    registerEmbedLabelPlistAction();
    registerEnvironmentPlistAction();
    registerAutomaticPlistAction();

    if (ObjcRuleClasses.useLaunchStoryboard(ruleContext)) {
      registerLaunchStoryboardPlistAction();
    }

    BundleMergeControlBytes bundleMergeControlBytes =
        new BundleMergeControlBytes(
            bundling, maybeSignedIpa, appleConfiguration, bundleSupport.targetDeviceFamilies());
    registerBundleMergeActions(
        maybeSignedIpa, bundling.getBundleContentArtifacts(), bundleMergeControlBytes);

    return this;
  }
  private Bundling bundling(
      RuleContext ruleContext,
      ObjcProvider objcProvider,
      String bundleDirFormat,
      String bundleName,
      DottedVersion minimumOsVersion) {
    ImmutableList<BundleableFile> extraBundleFiles;
    AppleConfiguration appleConfiguration = ruleContext.getFragment(AppleConfiguration.class);
    if (appleConfiguration.getBundlingPlatform() == Platform.IOS_DEVICE) {
      extraBundleFiles =
          ImmutableList.of(
              new BundleableFile(
                  new Attributes(ruleContext).provisioningProfile(),
                  PROVISIONING_PROFILE_BUNDLE_FILE));
    } else {
      extraBundleFiles = ImmutableList.of();
    }

    String primaryBundleId = null;
    String fallbackBundleId = null;

    if (ruleContext.attributes().isAttributeValueExplicitlySpecified("bundle_id")) {
      primaryBundleId = ruleContext.attributes().get("bundle_id", Type.STRING);
    } else {
      fallbackBundleId = ruleContext.attributes().get("bundle_id", Type.STRING);
    }

    Bundling.Builder bundling =
        new Builder()
            .setName(bundleName)
            // Architecture that determines which nested bundles are kept.
            .setArchitecture(appleConfiguration.getDependencySingleArchitecture())
            .setBundleDirFormat(bundleDirFormat)
            .addExtraBundleFiles(extraBundleFiles)
            .setObjcProvider(objcProvider)
            .addInfoplistInputFromRule(ruleContext)
            .addInfoplistInput(getGeneratedVersionPlist())
            .addInfoplistInput(getGeneratedEnvironmentPlist())
            .setAutomaticEntriesInfoplistInput(getGeneratedAutomaticPlist())
            .setIntermediateArtifacts(ObjcRuleClasses.intermediateArtifacts(ruleContext))
            .setPrimaryBundleId(primaryBundleId)
            .setFallbackBundleId(fallbackBundleId)
            .setMinimumOsVersion(minimumOsVersion);

    if (ObjcRuleClasses.useLaunchStoryboard(ruleContext)) {
      bundling.addInfoplistInput(getLaunchStoryboardPlist());
    }

    return bundling.build();
  }
Exemple #3
0
  /**
   * Returns any additional providers that need to be exported to the rule context to the passed
   * builder.
   */
  public Map<Class<? extends TransitiveInfoProvider>, TransitiveInfoProvider> getExtraProviders() {
    AppleConfiguration configuration = ruleContext.getFragment(AppleConfiguration.class);

    ImmutableMap.Builder<String, String> envBuilder = ImmutableMap.builder();

    envBuilder.putAll(configuration.getEnvironmentForIosAction());

    if (ruleContext.getConfiguration().isCodeCoverageEnabled()) {
      envBuilder.put(
          "COVERAGE_GCOV_PATH",
          ruleContext.getHostPrerequisiteArtifact(":gcov").getExecPathString());
    }

    return ImmutableMap.<Class<? extends TransitiveInfoProvider>, TransitiveInfoProvider>of(
        TestEnvironmentProvider.class, new TestEnvironmentProvider(envBuilder.build()));
  }
  /**
   * Returns a map containing entries that should be added to the merged plist. These are usually
   * generated by Xcode automatically during the build process.
   */
  private NSDictionary automaticEntries() {
    List<Integer> uiDeviceFamily =
        TargetDeviceFamily.UI_DEVICE_FAMILY_VALUES.get(bundleSupport.targetDeviceFamilies());
    AppleConfiguration appleConfiguration = ruleContext.getFragment(AppleConfiguration.class);
    Platform platform = appleConfiguration.getBundlingPlatform();
    ObjcConfiguration objcConfiguration = ObjcRuleClasses.objcConfiguration(ruleContext);

    NSDictionary result = new NSDictionary();

    if (uiDeviceFamily != null) {
      result.put("UIDeviceFamily", NSObject.wrap(uiDeviceFamily.toArray()));
    }
    result.put("DTPlatformName", NSObject.wrap(platform.getLowerCaseNameInPlist()));
    result.put(
        "DTSDKName",
        NSObject.wrap(platform.getLowerCaseNameInPlist() + appleConfiguration.getIosSdkVersion()));
    result.put("CFBundleSupportedPlatforms", new NSArray(NSObject.wrap(platform.getNameInPlist())));
    result.put("MinimumOSVersion", NSObject.wrap(objcConfiguration.getMinimumOs().toString()));

    return result;
  }
 private void registerEnvironmentPlistAction() {
   AppleConfiguration configuration = ruleContext.getFragment(AppleConfiguration.class);
   // Generates a .plist that contains environment values (such as the SDK used to build, the Xcode
   // version, etc), which are parsed from various .plist files of the OS, namely Xcodes' and
   // Platforms' plists.
   // The resulting file is meant to be merged with the final bundle.
   String platformWithVersion =
       String.format(
           "%s%s",
           configuration.getBundlingPlatform().getLowerCaseNameInPlist(),
           configuration.getIosSdkVersion());
   ruleContext.registerAction(
       ObjcRuleClasses.spawnOnDarwinActionBuilder()
           .setMnemonic("EnvironmentPlist")
           .addInput(attributes.environmentPlistScript())
           .setExecutable(attributes.environmentPlistScript())
           .addArguments("--platform", platformWithVersion)
           .addArguments("--output", getGeneratedEnvironmentPlist().getExecPathString())
           .addOutput(getGeneratedEnvironmentPlist())
           .build(ruleContext));
 }
Exemple #6
0
  /**
   * {@inheritDoc}
   *
   * <p>Creates a target, including registering actions, just as {@link #create(RuleContext)} does.
   * The difference between {@link #create(RuleContext)} and this method is that this method does
   * only what is needed to support tests on the environment besides generate the Xcodeproj file and
   * build the app and test {@code .ipa}s. The {@link #create(RuleContext)} method delegates to this
   * method.
   */
  @Override
  public final ConfiguredTarget create(RuleContext ruleContext)
      throws InterruptedException, RuleErrorException {
    ProtobufSupport protoSupport =
        new ProtobufSupport(ruleContext).registerGenerationActions().registerCompilationActions();
    Optional<ObjcProvider> protosObjcProvider = protoSupport.getObjcProvider();
    Optional<XcodeProvider> protosXcodeProvider = protoSupport.getXcodeProvider();

    ObjcCommon common = common(ruleContext, protosObjcProvider);

    if (!common.getCompilationArtifacts().get().getArchive().isPresent()) {
      ruleContext.ruleError(REQUIRES_SOURCE_ERROR);
    }

    if (!ruleContext.getFragment(AppleConfiguration.class).getIosMultiCpus().isEmpty()) {
      ruleContext.ruleError(NO_MULTI_CPUS_ERROR);
    }

    XcodeProvider.Builder xcodeProviderBuilder =
        new XcodeProvider.Builder().addPropagatedDependencies(protosXcodeProvider.asSet());

    NestedSetBuilder<Artifact> filesToBuild = NestedSetBuilder.stableOrder();
    addResourceFilesToBuild(ruleContext, common.getObjcProvider(), filesToBuild);

    XcodeProductType productType = getProductType(ruleContext);
    ExtraLinkArgs extraLinkArgs;
    Iterable<Artifact> extraLinkInputs;
    String bundleFormat;
    if (!isXcTest(ruleContext)) {
      extraLinkArgs = new ExtraLinkArgs();
      extraLinkInputs = ImmutableList.of();
      bundleFormat = ReleaseBundlingSupport.APP_BUNDLE_DIR_FORMAT;
    } else {
      XcodeProvider appIpaXcodeProvider =
          ruleContext.getPrerequisite(XCTEST_APP_ATTR, Mode.TARGET, XcodeProvider.class);
      xcodeProviderBuilder.setTestHost(appIpaXcodeProvider).setProductType(productType);

      XcTestAppProvider testApp = xcTestAppProvider(ruleContext);
      Artifact bundleLoader = testApp.getBundleLoader();

      // -bundle causes this binary to be linked as a bundle and not require an entry point
      // (i.e. main())
      // -bundle_loader causes the code in this test to have access to the symbols in the test rig,
      // or more specifically, the flag causes ld to consider the given binary when checking for
      // missing symbols.
      // -rpath @loader_path/Frameworks allows test bundles to load dylibs from the app's
      // Frameworks directory.
      extraLinkArgs =
          new ExtraLinkArgs(
              "-bundle",
              "-bundle_loader",
              bundleLoader.getExecPathString(),
              "-Xlinker",
              "-rpath",
              "-Xlinker",
              "@loader_path/Frameworks");

      extraLinkInputs = ImmutableList.of(bundleLoader);
      bundleFormat = ReleaseBundlingSupport.XCTEST_BUNDLE_DIR_FORMAT;

      filesToBuild.add(testApp.getIpa());
    }

    J2ObjcMappingFileProvider j2ObjcMappingFileProvider =
        J2ObjcMappingFileProvider.union(
            ruleContext.getPrerequisites("deps", Mode.TARGET, J2ObjcMappingFileProvider.class));
    J2ObjcEntryClassProvider j2ObjcEntryClassProvider =
        new J2ObjcEntryClassProvider.Builder()
            .addTransitive(
                ruleContext.getPrerequisites("deps", Mode.TARGET, J2ObjcEntryClassProvider.class))
            .build();

    new CompilationSupport(ruleContext)
        .registerLinkActions(
            common.getObjcProvider(),
            j2ObjcMappingFileProvider,
            j2ObjcEntryClassProvider,
            extraLinkArgs,
            extraLinkInputs,
            DsymOutputType.TEST)
        .registerCompileAndArchiveActions(common)
        .registerFullyLinkAction(
            common.getObjcProvider(),
            ruleContext.getImplicitOutputArtifact(CompilationSupport.FULLY_LINKED_LIB))
        .addXcodeSettings(xcodeProviderBuilder, common)
        .validateAttributes();

    AppleConfiguration appleConfiguration = ruleContext.getFragment(AppleConfiguration.class);
    new ReleaseBundlingSupport(
            ruleContext,
            common.getObjcProvider(),
            LinkedBinary.LOCAL_AND_DEPENDENCIES,
            bundleFormat,
            appleConfiguration.getMinimumOsForPlatformType(PlatformType.IOS),
            appleConfiguration.getMultiArchPlatform(PlatformType.IOS))
        .registerActions(DsymOutputType.TEST)
        .addXcodeSettings(xcodeProviderBuilder)
        .addFilesToBuild(filesToBuild, Optional.of(DsymOutputType.TEST))
        .validateResources()
        .validateAttributes();

    new ResourceSupport(ruleContext).validateAttributes().addXcodeSettings(xcodeProviderBuilder);

    new XcodeSupport(ruleContext)
        .addXcodeSettings(xcodeProviderBuilder, common.getObjcProvider(), productType)
        .addDependencies(xcodeProviderBuilder, new Attribute("bundles", Mode.TARGET))
        .addDependencies(xcodeProviderBuilder, new Attribute("deps", Mode.TARGET))
        .addNonPropagatedDependencies(
            xcodeProviderBuilder, new Attribute("non_propagated_deps", Mode.TARGET))
        .addFilesToBuild(filesToBuild)
        .registerActions(xcodeProviderBuilder.build());

    XcodeProvider xcodeProvider = xcodeProviderBuilder.build();
    NestedSet<Artifact> filesToBuildSet = filesToBuild.build();

    Runfiles.Builder runfilesBuilder =
        new Runfiles.Builder(
                ruleContext.getWorkspaceName(),
                ruleContext.getConfiguration().legacyExternalRunfiles())
            .addRunfiles(ruleContext, RunfilesProvider.DEFAULT_RUNFILES);

    NestedSetBuilder<Artifact> filesToBuildBuilder =
        NestedSetBuilder.<Artifact>stableOrder().addTransitive(filesToBuildSet);

    InstrumentedFilesProvider instrumentedFilesProvider =
        new CompilationSupport(ruleContext).getInstrumentedFilesProvider(common);

    TestSupport testSupport =
        new TestSupport(ruleContext)
            .registerTestRunnerActions()
            .addRunfiles(runfilesBuilder, instrumentedFilesProvider)
            .addFilesToBuild(filesToBuildBuilder);

    Artifact executable = testSupport.generatedTestScript();

    Runfiles runfiles = runfilesBuilder.build();
    RunfilesSupport runfilesSupport =
        RunfilesSupport.withExecutable(ruleContext, runfiles, executable);

    ImmutableMap.Builder<String, String> execInfoMapBuilder = new ImmutableMap.Builder<>();
    execInfoMapBuilder.put(ExecutionRequirements.REQUIRES_DARWIN, "");
    if (ruleContext.getFragment(ObjcConfiguration.class).runMemleaks()) {
      execInfoMapBuilder.put("nosandbox", "");
    }

    return new RuleConfiguredTargetBuilder(ruleContext)
        .setFilesToBuild(filesToBuildBuilder.build())
        .addProvider(xcodeProvider)
        .addProvider(RunfilesProvider.simple(runfiles))
        .addProvider(new ExecutionInfoProvider(execInfoMapBuilder.build()))
        .addProvider(InstrumentedFilesProvider.class, instrumentedFilesProvider)
        .addProviders(testSupport.getExtraProviders())
        .setRunfilesSupport(runfilesSupport, executable)
        .build();
  }