// Copyright 2015 Google Inc. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.google.devtools.build.lib.rules.objc; import com.google.common.base.Optional; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode; import com.google.devtools.build.lib.analysis.RuleContext; import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; import com.google.devtools.build.lib.rules.objc.ObjcActionsBuilder.ExtraActoolArgs; import com.google.devtools.build.lib.rules.objc.XcodeProvider.Builder; import com.google.devtools.build.xcode.common.TargetDeviceFamily; import java.util.Set; /** * Support for generating iOS bundles which contain metadata (a plist file), assets, resources and * optionally a binary: registers actions that assemble resources and merge plists, provides data * to providers and validates bundle-related attributes. * *

Methods on this class can be called in any order without impacting the result. */ final class BundleSupport { private final RuleContext ruleContext; private final Set targetDeviceFamilies; private final ExtraActoolArgs extraActoolArgs; private final Bundling bundling; /** * Returns merging instructions for a bundle's {@code Info.plist}. * * @param ruleContext context this bundle is constructed in * @param objcProvider provider containing all dependencies' information as well as some of this * rule's * @param optionsProvider provider containing options and plist settings for this rule and its * dependencies */ static InfoplistMerging infoPlistMerging(RuleContext ruleContext, ObjcProvider objcProvider, OptionsProvider optionsProvider) { IntermediateArtifacts intermediateArtifacts = ObjcRuleClasses.intermediateArtifacts(ruleContext); return new InfoplistMerging.Builder(ruleContext) .setIntermediateArtifacts(intermediateArtifacts) .setInputPlists(NestedSetBuilder.stableOrder() .addTransitive(optionsProvider.getInfoplists()) .addAll(actoolPartialInfoplist(ruleContext, objcProvider).asSet()) .build()) .setPlmerge(ruleContext.getExecutablePrerequisite("$plmerge", Mode.HOST)) .build(); } /** * Creates a new bundle support with no special {@code actool} arguments. * * @param ruleContext context this bundle is constructed in * @param targetDeviceFamilies device families used in asset catalogue construction * @param bundling bundle information as configured for this rule */ public BundleSupport( RuleContext ruleContext, Set targetDeviceFamilies, Bundling bundling) { this(ruleContext, targetDeviceFamilies, bundling, new ExtraActoolArgs()); } /** * Creates a new bundle support. * * @param ruleContext context this bundle is constructed in * @param targetDeviceFamilies device families used in asset catalogue construction * @param bundling bundle information as configured for this rule * @param extraActoolArgs any additional parameters to be used for invoking {@code actool} */ public BundleSupport(RuleContext ruleContext, Set targetDeviceFamilies, Bundling bundling, ExtraActoolArgs extraActoolArgs) { this.ruleContext = ruleContext; this.targetDeviceFamilies = targetDeviceFamilies; this.extraActoolArgs = extraActoolArgs; this.bundling = bundling; } /** * Registers actions required for constructing this bundle, namely merging all involved {@code * Info.plist} files and generating asset catalogues. * * @param objcProvider source of information from this rule's attributes and its dependencies * * @return this bundle support */ BundleSupport registerActions(ObjcProvider objcProvider) { registerMergeInfoplistAction(); registerActoolActionIfNecessary(objcProvider); return this; } /** * Adds any Xcode settings related to this bundle to the given provider builder. * * @return this bundle support */ BundleSupport addXcodeSettings(Builder xcodeProviderBuilder) { xcodeProviderBuilder.setInfoplistMerging(bundling.getInfoplistMerging()); return this; } private void registerMergeInfoplistAction() { // TODO(bazel-team): Move action implementation from InfoplistMerging to this class. ruleContext.registerAction(bundling.getInfoplistMerging().getMergeAction()); } private void registerActoolActionIfNecessary(ObjcProvider objcProvider) { Optional actoolzipOutput = bundling.getActoolzipOutput(); if (!actoolzipOutput.isPresent()) { return; } ObjcActionsBuilder actionsBuilder = ObjcRuleClasses.actionsBuilder(ruleContext); Artifact actoolPartialInfoplist = actoolPartialInfoplist(ruleContext, objcProvider).get(); actionsBuilder.registerActoolzipAction( new ObjcRuleClasses.Tools(ruleContext), objcProvider, actoolzipOutput.get(), actoolPartialInfoplist, extraActoolArgs, targetDeviceFamilies); } /** * Returns the artifact that is a plist file generated by an invocation of {@code actool} or * {@link Optional#absent()} if no asset catalogues are present in this target and its * dependencies. * *

All invocations of {@code actool} generate this kind of plist file, which contains metadata * about the {@code app_icon} and {@code launch_image} if supplied. If neither an app icon or a * launch image was supplied, the plist file generated is empty. */ private static Optional actoolPartialInfoplist( RuleContext ruleContext, ObjcProvider objcProvider) { if (objcProvider.hasAssetCatalogs()) { IntermediateArtifacts intermediateArtifacts = ObjcRuleClasses.intermediateArtifacts(ruleContext); return Optional.of(intermediateArtifacts.actoolPartialInfoplist()); } else { return Optional.absent(); } } }