diff options
author | 2016-03-22 18:23:03 +0000 | |
---|---|---|
committer | 2016-03-23 12:19:51 +0000 | |
commit | 73f2a45d3a601b43e72c866e44f4ba3eaa782aeb (patch) | |
tree | 7a5ab2d1524f02526d22e6de0f2d3f7bd8f15779 /src | |
parent | a65d0ee1f9376820f87309a3b81502ad14614583 (diff) |
Introduce ReleaseBundling class to contain all application specific information required for creating a release bundle.
--
MOS_MIGRATED_REVID=117843546
Diffstat (limited to 'src')
5 files changed, 587 insertions, 167 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/BundleSupport.java b/src/main/java/com/google/devtools/build/lib/rules/objc/BundleSupport.java index 3900c701a0..3123ded3d0 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/BundleSupport.java +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/BundleSupport.java @@ -35,15 +35,11 @@ import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.lib.rules.apple.AppleConfiguration; import com.google.devtools.build.lib.rules.apple.AppleToolchain; import com.google.devtools.build.lib.rules.apple.Platform; -import com.google.devtools.build.lib.rules.objc.TargetDeviceFamily.InvalidFamilyNameException; -import com.google.devtools.build.lib.rules.objc.TargetDeviceFamily.RepeatedFamilyNameException; import com.google.devtools.build.lib.rules.objc.XcodeProvider.Builder; -import com.google.devtools.build.lib.syntax.Type; import com.google.devtools.build.lib.vfs.FileSystemUtils; import com.google.devtools.build.lib.vfs.PathFragment; import java.util.HashMap; -import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; @@ -216,20 +212,18 @@ final class BundleSupport { } /** - * Returns a set containing the {@link TargetDeviceFamily} values - * which this bundle is targeting. Returns an empty set for any - * invalid value of the target device families attribute. + * Returns a set containing the {@link TargetDeviceFamily} values which this bundle is targeting. + * Returns an empty set for any invalid value of the target device families attribute. */ ImmutableSet<TargetDeviceFamily> targetDeviceFamilies() { - return attributes.families(); + return bundling.getTargetDeviceFamilies(); } private void registerInterfaceBuilderActions(ObjcProvider objcProvider) { - IntermediateArtifacts intermediateArtifacts = - ObjcRuleClasses.intermediateArtifacts(ruleContext); for (Artifact storyboardInput : objcProvider.get(ObjcProvider.STORYBOARD)) { String archiveRoot = BundleableFile.flatBundlePath(storyboardInput.getExecPath()) + "c"; - Artifact zipOutput = intermediateArtifacts.compiledStoryboardZip(storyboardInput); + Artifact zipOutput = bundling.getIntermediateArtifacts() + .compiledStoryboardZip(storyboardInput); ruleContext.registerAction( ObjcRuleClasses.spawnXcrunActionBuilder(ruleContext) @@ -254,7 +248,7 @@ final class BundleSupport { .add("--module") .add(ruleContext.getLabel().getName()); - for (TargetDeviceFamily targetDeviceFamily : attributes.families()) { + for (TargetDeviceFamily targetDeviceFamily : targetDeviceFamilies()) { commandLine.add("--target-device").add(targetDeviceFamily.name().toLowerCase(Locale.US)); } @@ -265,10 +259,8 @@ final class BundleSupport { private void registerMomczipActions(ObjcProvider objcProvider) { AppleConfiguration appleConfiguration = ruleContext.getFragment(AppleConfiguration.class); - IntermediateArtifacts intermediateArtifacts = - ObjcRuleClasses.intermediateArtifacts(ruleContext); Iterable<Xcdatamodel> xcdatamodels = Xcdatamodels.xcdatamodels( - intermediateArtifacts, objcProvider.get(ObjcProvider.XCDATAMODEL)); + bundling.getIntermediateArtifacts(), objcProvider.get(ObjcProvider.XCDATAMODEL)); for (Xcdatamodel datamodel : xcdatamodels) { Artifact outputZip = datamodel.getOutputZip(); ruleContext.registerAction( @@ -292,10 +284,8 @@ final class BundleSupport { } private void registerConvertXibsActions(ObjcProvider objcProvider) { - IntermediateArtifacts intermediateArtifacts = - ObjcRuleClasses.intermediateArtifacts(ruleContext); for (Artifact original : objcProvider.get(ObjcProvider.XIB)) { - Artifact zipOutput = intermediateArtifacts.compiledXibFileZip(original); + Artifact zipOutput = bundling.getIntermediateArtifacts().compiledXibFileZip(original); String archiveRoot = BundleableFile.flatBundlePath( FileSystemUtils.replaceExtension(original.getExecPath(), ".nib")); @@ -311,10 +301,8 @@ final class BundleSupport { } private void registerConvertStringsActions(ObjcProvider objcProvider) { - IntermediateArtifacts intermediateArtifacts = - ObjcRuleClasses.intermediateArtifacts(ruleContext); for (Artifact strings : objcProvider.get(ObjcProvider.STRINGS)) { - Artifact bundled = intermediateArtifacts.convertedStringsFile(strings); + Artifact bundled = bundling.getIntermediateArtifacts().convertedStringsFile(strings); ruleContext.registerAction(ObjcRuleClasses.spawnXcrunActionBuilder(ruleContext) .setMnemonic("ConvertStringsPlist") .setExecutable(new PathFragment("/usr/bin/plutil")) @@ -341,9 +329,8 @@ final class BundleSupport { if (!bundling.needsToMergeInfoplist()) { return; // Nothing to do here. } - - Artifact plMergeControlArtifact = - ObjcRuleClasses.artifactByAppendingToBaseName(ruleContext, ".plmerge-control"); + + Artifact plMergeControlArtifact = baseNameArtifact(ruleContext, ".plmerge-control"); ruleContext.registerAction( new BinaryFileWriteAction( @@ -359,17 +346,32 @@ final class BundleSupport { .addArgument("--control") .addInputArgument(plMergeControlArtifact) .addTransitiveInputs(mergingContentArtifacts) - .addOutput(ObjcRuleClasses.intermediateArtifacts(ruleContext).mergedInfoplist()) + .addOutput(bundling.getIntermediateArtifacts().mergedInfoplist()) .build(ruleContext)); } + /** + * Returns an {@link Artifact} with name prefixed with prefix given in {@link Bundling} if + * available. This helps in creating unique artifact name when multiple bundles are created + * with a different name than the target name. + */ + private Artifact baseNameArtifact(RuleContext ruleContext, String artifactName) { + String prefixedArtifactName; + if (bundling.getArtifactPrefix() != null) { + prefixedArtifactName = String.format("-%s%s", bundling.getArtifactPrefix(), artifactName); + } else { + prefixedArtifactName = artifactName; + } + return ObjcRuleClasses.artifactByAppendingToBaseName(ruleContext, prefixedArtifactName); + } + private void registerActoolActionIfNecessary(ObjcProvider objcProvider) { Optional<Artifact> actoolzipOutput = bundling.getActoolzipOutput(); if (!actoolzipOutput.isPresent()) { return; } - Artifact actoolPartialInfoplist = actoolPartialInfoplist(ruleContext, objcProvider).get(); + Artifact actoolPartialInfoplist = actoolPartialInfoplist(objcProvider).get(); Artifact zipOutput = actoolzipOutput.get(); // TODO(bazel-team): Do not use the deploy jar explicitly here. There is currently a bug where @@ -404,7 +406,7 @@ final class BundleSupport { .add("--minimum-deployment-target") .add(bundling.getMinimumOsVersion().toString()); - for (TargetDeviceFamily targetDeviceFamily : attributes.families()) { + for (TargetDeviceFamily targetDeviceFamily : targetDeviceFamilies()) { commandLine.add("--target-device").add(targetDeviceFamily.name().toLowerCase(Locale.US)); } @@ -424,12 +426,9 @@ final class BundleSupport { * 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<Artifact> actoolPartialInfoplist( - RuleContext ruleContext, ObjcProvider objcProvider) { + private Optional<Artifact> actoolPartialInfoplist(ObjcProvider objcProvider) { if (objcProvider.hasAssetCatalogs()) { - IntermediateArtifacts intermediateArtifacts = - ObjcRuleClasses.intermediateArtifacts(ruleContext); - return Optional.of(intermediateArtifacts.actoolPartialInfoplist()); + return Optional.of(bundling.getIntermediateArtifacts().actoolPartialInfoplist()); } else { return Optional.absent(); } @@ -453,21 +452,6 @@ final class BundleSupport { } /** - * Returns the value of the {@code families} attribute in a form - * that is more useful than a list of strings. Returns an empty - * set for any invalid {@code families} attribute value, including - * an empty list. - */ - ImmutableSet<TargetDeviceFamily> families() { - List<String> rawFamilies = ruleContext.attributes().get("families", Type.STRING_LIST); - try { - return ImmutableSet.copyOf(TargetDeviceFamily.fromNamesInRule(rawFamilies)); - } catch (InvalidFamilyNameException | RepeatedFamilyNameException e) { - return ImmutableSet.of(); - } - } - - /** * Returns the location of the ibtoolwrapper tool. */ FilesToRunProvider ibtoolWrapper() { diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/Bundling.java b/src/main/java/com/google/devtools/build/lib/rules/objc/Bundling.java index ec9da712c7..c9b83efdae 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/Bundling.java +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/Bundling.java @@ -30,6 +30,7 @@ import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.BundlingR import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode; @@ -63,6 +64,8 @@ final class Bundling { private String fallbackBundleId; private String architecture; private DottedVersion minimumOsVersion; + private ImmutableSet<TargetDeviceFamily> families; + private String artifactPrefix; public Builder setName(String name) { this.name = name; @@ -104,6 +107,15 @@ final class Bundling { } /** + * Adds the given list of artifacts representing {@code Info.plist}s that are to be merged into + * this bundle's {@code Info.plist}. + */ + public Builder addInfoplistInputs(Iterable<Artifact> infoplists) { + this.infoplistInputs.addAll(infoplists); + return this; + } + + /** * Adds an artifact representing an {@code Info.plist} that contains automatic entries * generated by xcode. */ @@ -137,12 +149,12 @@ final class Bundling { this.intermediateArtifacts = intermediateArtifacts; return this; } - + public Builder setPrimaryBundleId(String primaryId) { this.primaryBundleId = primaryId; return this; } - + public Builder setFallbackBundleId(String fallbackId) { this.fallbackBundleId = fallbackId; return this; @@ -157,6 +169,16 @@ final class Bundling { return this; } + public Builder setTargetDeviceFamilies(ImmutableSet<TargetDeviceFamily> families) { + this.families = families; + return this; + } + + public Builder setArtifactPrefix(String artifactPrefix) { + this.artifactPrefix = artifactPrefix; + return this; + } + private static NestedSet<Artifact> nestedBundleContentArtifacts(Iterable<Bundling> bundles) { NestedSetBuilder<Artifact> artifacts = NestedSetBuilder.stableOrder(); for (Bundling bundle : bundles) { @@ -259,7 +281,7 @@ final class Bundling { public Bundling build() { Preconditions.checkNotNull(intermediateArtifacts, "intermediateArtifacts"); - + Preconditions.checkNotNull(families, "families"); NestedSet<Artifact> bundleInfoplistInputs = bundleInfoplistInputs(); Optional<Artifact> bundleInfoplist = bundleInfoplist(bundleInfoplistInputs); Optional<Artifact> actoolzipOutput = actoolzipOutput(); @@ -295,7 +317,10 @@ final class Bundling { minimumOsVersion, bundleInfoplistInputs, automaticEntriesInfoplistInput, - objcProvider.get(NESTED_BUNDLE)); + objcProvider.get(NESTED_BUNDLE), + families, + intermediateArtifacts, + artifactPrefix); } } @@ -320,6 +345,9 @@ final class Bundling { private final NestedSet<Artifact> infoplistInputs; private final NestedSet<Bundling> nestedBundlings; private Artifact automaticEntriesInfoplistInput; + private final ImmutableSet<TargetDeviceFamily> families; + private final IntermediateArtifacts intermediateArtifacts; + private final String artifactPrefix; private Bundling( String name, @@ -336,7 +364,10 @@ final class Bundling { DottedVersion minimumOsVersion, NestedSet<Artifact> infoplistInputs, Artifact automaticEntriesInfoplistInput, - NestedSet<Bundling> nestedBundlings) { + NestedSet<Bundling> nestedBundlings, + ImmutableSet<TargetDeviceFamily> families, + IntermediateArtifacts intermediateArtifacts, + String artifactPrefix) { this.nestedBundlings = Preconditions.checkNotNull(nestedBundlings); this.name = Preconditions.checkNotNull(name); this.bundleDirFormat = Preconditions.checkNotNull(bundleDirFormat); @@ -352,6 +383,9 @@ final class Bundling { this.minimumOsVersion = Preconditions.checkNotNull(minimumOsVersion); this.infoplistInputs = Preconditions.checkNotNull(infoplistInputs); this.automaticEntriesInfoplistInput = automaticEntriesInfoplistInput; + this.families = Preconditions.checkNotNull(families); + this.intermediateArtifacts = intermediateArtifacts; + this.artifactPrefix = artifactPrefix; } /** @@ -401,7 +435,7 @@ final class Bundling { public Optional<Artifact> getBundleInfoplist() { return bundleInfoplist; } - + /** * Returns all info plists that need to be merged into this bundle's {@link #getBundleInfoplist() * info plist}, other than that plist that contains blaze-generated automatic entires. @@ -428,7 +462,7 @@ final class Bundling { } return result.build(); } - + /** * Returns {@code true} if this bundle requires merging of its {@link #getBundleInfoplist() info * plist}. @@ -505,4 +539,27 @@ final class Bundling { public DottedVersion getMinimumOsVersion() { return minimumOsVersion; } + + /** + * Returns the list of {@link TargetDeviceFamily} values this bundle is targeting. + * If empty, the default values specified by "families" attribute will be used. + */ + public ImmutableSet<TargetDeviceFamily> getTargetDeviceFamilies() { + return families; + } + + /** + * Returns {@link IntermediateArtifacts} required to create this bundle. + */ + public IntermediateArtifacts getIntermediateArtifacts() { + return intermediateArtifacts; + } + + /** + * Returns the prefix to be added to all generated artifact names, can be null. This is useful + * to disambiguate artifacts for multiple bundles created with different names withing same rule. + */ + public String getArtifactPrefix() { + return artifactPrefix; + } } diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcBundleLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcBundleLibrary.java index 1827df916e..6fa174900d 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcBundleLibrary.java +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcBundleLibrary.java @@ -17,6 +17,7 @@ package com.google.devtools.build.lib.rules.objc; import static com.google.devtools.build.lib.rules.objc.ObjcProvider.NESTED_BUNDLE; import static com.google.devtools.build.lib.rules.objc.XcodeProductType.BUNDLE; +import com.google.common.collect.ImmutableSet; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.analysis.ConfiguredTarget; import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode; @@ -25,6 +26,11 @@ import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory; import com.google.devtools.build.lib.rules.apple.AppleConfiguration; import com.google.devtools.build.lib.rules.objc.ObjcCommon.ResourceAttributes; +import com.google.devtools.build.lib.rules.objc.TargetDeviceFamily.InvalidFamilyNameException; +import com.google.devtools.build.lib.rules.objc.TargetDeviceFamily.RepeatedFamilyNameException; +import com.google.devtools.build.lib.syntax.Type; + +import java.util.List; /** * Implementation for {@code objc_bundle_library}. @@ -77,6 +83,19 @@ public class ObjcBundleLibrary implements RuleConfiguredTargetFactory { ObjcRuleClasses.intermediateArtifacts(ruleContext); ObjcConfiguration objcConfiguration = ObjcRuleClasses.objcConfiguration(ruleContext); AppleConfiguration appleConfiguration = ruleContext.getFragment(AppleConfiguration.class); + + ImmutableSet<TargetDeviceFamily> families = null; + List<String> rawFamilies = ruleContext.attributes().get("families", Type.STRING_LIST); + try { + families = ImmutableSet.copyOf(TargetDeviceFamily.fromNamesInRule(rawFamilies)); + } catch (InvalidFamilyNameException | RepeatedFamilyNameException e) { + families = ImmutableSet.of(); + } + + if (families.isEmpty()) { + ruleContext.attributeError("families", ReleaseBundling.INVALID_FAMILIES_ERROR); + } + return new Bundling.Builder() .setName(ruleContext.getLabel().getName()) .setArchitecture(appleConfiguration.getIosCpu()) @@ -85,6 +104,7 @@ public class ObjcBundleLibrary implements RuleConfiguredTargetFactory { .addInfoplistInputFromRule(ruleContext) .setIntermediateArtifacts(intermediateArtifacts) .setMinimumOsVersion(objcConfiguration.getMinimumOs()) + .setTargetDeviceFamilies(families) .build(); } diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ReleaseBundling.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ReleaseBundling.java new file mode 100644 index 0000000000..a78f0077d1 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ReleaseBundling.java @@ -0,0 +1,361 @@ +// Copyright 2016 The Bazel Authors. 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.annotations.VisibleForTesting; +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableSet; +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.NestedSet; +import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; +import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; +import com.google.devtools.build.lib.rules.objc.TargetDeviceFamily.InvalidFamilyNameException; +import com.google.devtools.build.lib.rules.objc.TargetDeviceFamily.RepeatedFamilyNameException; +import com.google.devtools.build.lib.syntax.Type; +import com.google.devtools.build.lib.util.Preconditions; + +import java.util.List; + +/** + * Contains information regarding the creation of a released bundle such as an application + * or extension. The information which generally includes app icons, launch image, targeted devices + * and other data for potential signing is used to create a releasable bundle out of the bundle + * created using {@link Bundling} object. + */ +@Immutable +final class ReleaseBundling { + static final class Builder { + private Artifact ipaArtifact; + private String bundleId; + private String primaryBundleId; + private String fallbackBundleId; + private String appIcon; + private String launchImage; + private Artifact launchStoryboard; + private Artifact provisioningProfile; + private String provisioningProfileAttributeName; + private final NestedSetBuilder<Artifact> infoplistInputs = NestedSetBuilder.stableOrder(); + private Iterable<Artifact> infoPlistsFromRule; + private ImmutableSet<TargetDeviceFamily> families; + private IntermediateArtifacts intermediateArtifacts; + private String artifactPrefix; + + public Builder setIpaArtifact(Artifact ipaArtifact) { + this.ipaArtifact = ipaArtifact; + return this; + } + + public Builder setBundleId(String bundleId) { + this.bundleId = bundleId; + return this; + } + + public Builder setPrimaryBundleId(String primaryId) { + this.primaryBundleId = primaryId; + return this; + } + + public Builder setFallbackBundleId(String fallbackId) { + this.fallbackBundleId = fallbackId; + return this; + } + + public Builder setAppIcon(String appIcon) { + this.appIcon = appIcon; + return this; + } + + public Builder setLaunchImage(String launchImage) { + this.launchImage = launchImage; + return this; + } + + public Builder setLaunchStoryboard(Artifact launchStoryboard) { + this.launchStoryboard = launchStoryboard; + return this; + } + + public Builder setProvisioningProfile(Artifact provisioningProfile) { + this.provisioningProfile = provisioningProfile; + return this; + } + + public Builder setProvisioningProfileAttributeName(String provisioningProfileAttributeName) { + this.provisioningProfileAttributeName = provisioningProfileAttributeName; + return this; + } + + public Builder addInfoplistInput(Artifact infoPlist) { + this.infoplistInputs.add(infoPlist); + return this; + } + + public Builder addInfoplistInputs(Iterable<Artifact> infoplists) { + this.infoplistInputs.addAll(infoplists); + return this; + } + + public Builder setInfoPlistsFromRule(Iterable<Artifact> infoPlistsFromRule) { + this.infoPlistsFromRule = infoPlistsFromRule; + return this; + } + + public Builder setIntermediateArtifacts(IntermediateArtifacts intermediateArtifacts) { + this.intermediateArtifacts = intermediateArtifacts; + return this; + } + + public Builder setTargetDeviceFamilies(ImmutableSet<TargetDeviceFamily> families) { + this.families = families; + return this; + } + + public Builder setArtifactPrefix(String artifactPrefix) { + this.artifactPrefix = artifactPrefix; + return this; + } + + public ReleaseBundling build() { + Preconditions.checkNotNull(intermediateArtifacts, "intermediateArtifacts"); + Preconditions.checkNotNull(families, "families"); + return new ReleaseBundling( + ipaArtifact, + bundleId, + primaryBundleId, + fallbackBundleId, + appIcon, + launchImage, + launchStoryboard, + provisioningProfile, + provisioningProfileAttributeName, + infoplistInputs.build(), + infoPlistsFromRule, + families, + intermediateArtifacts, + artifactPrefix); + } + } + + /** + * Returns a {@link ReleaseBundling} object constructed using the information available in given + * context. + */ + public static ReleaseBundling releaseBundling(RuleContext ruleContext) + throws InterruptedException { + Preconditions.checkState(!Strings.isNullOrEmpty( + ruleContext.attributes().get("bundle_id", Type.STRING)), + "requires a bundle_id value"); + String primaryBundleId = null; + String fallbackBundleId = null; + Artifact provisioningProfile; + + if (ruleContext.attributes().isAttributeValueExplicitlySpecified("bundle_id")) { + primaryBundleId = ruleContext.attributes().get("bundle_id", Type.STRING); + } else { + fallbackBundleId = ruleContext.attributes().get("bundle_id", Type.STRING); + } + + Artifact explicitProvisioningProfile = + ruleContext.getPrerequisiteArtifact("provisioning_profile", Mode.TARGET); + if (explicitProvisioningProfile != null) { + provisioningProfile = explicitProvisioningProfile; + } else { + provisioningProfile = ruleContext.getPrerequisiteArtifact(":default_provisioning_profile", + Mode.TARGET); + } + + ImmutableSet<TargetDeviceFamily> families = null; + List<String> rawFamilies = ruleContext.attributes().get("families", Type.STRING_LIST); + try { + families = ImmutableSet.copyOf(TargetDeviceFamily.fromNamesInRule(rawFamilies)); + } catch (InvalidFamilyNameException | RepeatedFamilyNameException e) { + families = ImmutableSet.of(); + } + + if (families.isEmpty()) { + ruleContext.attributeError("families", INVALID_FAMILIES_ERROR); + } + + return new ReleaseBundling.Builder() + .setIpaArtifact(ruleContext.getImplicitOutputArtifact(ReleaseBundlingSupport.IPA)) + .setBundleId(ruleContext.attributes().get("bundle_id", Type.STRING)) + .setPrimaryBundleId(primaryBundleId) + .setFallbackBundleId(fallbackBundleId) + .setAppIcon(Strings.emptyToNull(ruleContext.attributes().get("app_icon", Type.STRING))) + .setLaunchImage(Strings.emptyToNull( + ruleContext.attributes().get("launch_image", Type.STRING))) + .setLaunchStoryboard(ruleContext.getPrerequisiteArtifact("launch_storyboard", Mode.TARGET)) + .setProvisioningProfile(provisioningProfile) + .setProvisioningProfileAttributeName("provisioning_profile") + .setTargetDeviceFamilies(families) + .setIntermediateArtifacts(ObjcRuleClasses.intermediateArtifacts(ruleContext)) + .build(); + } + + @VisibleForTesting + static final String INVALID_FAMILIES_ERROR = + "Expected one or two strings from the list 'iphone', 'ipad'"; + private final Artifact ipaArtifact; + private final String bundleId; + private final String fallbackBundleId; + private final String primaryBundleId; + private final String appIcon; + private final String launchImage; + private final Artifact launchStoryboard; + private final Artifact provisioningProfile; + private final String provisioningProfileAttributeName; + private final NestedSet<Artifact> infoplistInputs; + private final ImmutableSet<TargetDeviceFamily> families; + private final IntermediateArtifacts intermediateArtifacts; + private final Iterable<Artifact> infoPlistsFromRule; + private final String artifactPrefix; + + private ReleaseBundling( + Artifact ipaArtifact, + String bundleId, + String primaryBundleId, + String fallbackBundleId, + String appIcon, + String launchImage, + Artifact launchStoryboard, + Artifact provisioningProfile, + String provisioningProfileAttributeName, + NestedSet<Artifact> infoplistInputs, + Iterable<Artifact> infoPlistsFromRule, + ImmutableSet<TargetDeviceFamily> families, + IntermediateArtifacts intermediateArtifacts, + String artifactPrefix) { + this.ipaArtifact = Preconditions.checkNotNull(ipaArtifact); + this.bundleId = bundleId; + this.primaryBundleId = primaryBundleId; + this.fallbackBundleId = fallbackBundleId; + this.appIcon = appIcon; + this.launchImage = launchImage; + this.launchStoryboard = launchStoryboard; + this.provisioningProfile = provisioningProfile; + this.provisioningProfileAttributeName = + Preconditions.checkNotNull(provisioningProfileAttributeName); + this.infoplistInputs = Preconditions.checkNotNull(infoplistInputs); + this.infoPlistsFromRule = infoPlistsFromRule; + this.families = Preconditions.checkNotNull(families); + this.intermediateArtifacts = Preconditions.checkNotNull(intermediateArtifacts); + this.artifactPrefix = artifactPrefix; + } + + /** + * Returns the {@link Artifact} containing the final ipa bundle. + */ + public Artifact getIpaArtifact() { + return ipaArtifact; + } + + /** + * Returns the identifier of this bundle. + */ + public String getBundleId() { + return bundleId; + } + + /** + * Returns primary bundle ID to use, can be null. + */ + public String getPrimaryBundleId() { + return primaryBundleId; + } + + /** + * Returns fallback bundle ID to use when primary isn't set. + */ + public String getFallbackBundleId() { + return fallbackBundleId; + } + + /** + * Returns the app icon name for this bundle, can be null. + */ + public String getAppIcon() { + return appIcon; + } + + /** + * Returns the launch image name for this bundle, can be null. + */ + public String getLaunchImage() { + return launchImage; + } + + /** + * Returns an {@link Artifact} containing launch storyboard for this bundle, can be null. + */ + public Artifact getLaunchStoryboard() { + return launchStoryboard; + } + + /** + * Returns an {@link Artifact} containing provisioning profile used to sign this bundle, + * can be null. + */ + public Artifact getProvisioningProfile() { + return provisioningProfile; + } + + /** + * Returns the list of plists to be merged to final bundle. + */ + public NestedSet<Artifact> getInfoplistInputs() { + return infoplistInputs; + } + + /** + * Returns the list of {@link TargetDeviceFamily} values this bundle is targeting. + * If empty, the default values specified by "families" attribute will be used. + */ + public ImmutableSet<TargetDeviceFamily> getTargetDeviceFamilies() { + return families; + } + + /** + * Returns {@link IntermediateArtifacts} used to create this bundle. + */ + public IntermediateArtifacts getIntermediateArtifacts() { + return intermediateArtifacts; + } + + /** + * Returns the name of the attribute which is used to specifiy the provisioning profile. + */ + public String getProvisioningProfileAttrName() { + return provisioningProfileAttributeName; + } + + /** + * Adds any info plists specified in the given rule's {@code infoplists} attribute as inputs to + * this bundle's {@code Info.plist} (which is merged from any such added plists plus some + * additional information). + */ + public Iterable<Artifact> getInfoPlistsFromRule() { + return infoPlistsFromRule; + } + + /** + * Returns the prefix to be added to all generated artifact names, can be null. This is useful + * to disambiguate artifacts for multiple bundles created with different names withing same rule. + */ + public String getArtifactPrefix() { + return artifactPrefix; + } +} diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ReleaseBundlingSupport.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ReleaseBundlingSupport.java index c6dc2740a8..40c52be628 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/ReleaseBundlingSupport.java +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ReleaseBundlingSupport.java @@ -56,7 +56,6 @@ import com.google.devtools.build.lib.rules.apple.Platform; import com.google.devtools.build.lib.rules.objc.BundleSupport.ExtraActoolArgs; import com.google.devtools.build.lib.rules.objc.Bundling.Builder; import com.google.devtools.build.lib.shell.ShellUtils; -import com.google.devtools.build.lib.syntax.Type; import com.google.devtools.build.xcode.xcodegen.proto.XcodeGenProtos.XcodeprojBuildSetting; import com.dd.plist.NSArray; @@ -88,9 +87,6 @@ public final class ReleaseBundlingSupport { static final String NO_ASSET_CATALOG_ERROR_FORMAT = "a value was specified (%s), but this app does not have any asset catalogs"; @VisibleForTesting - static final String INVALID_FAMILIES_ERROR = - "Expected one or two strings from the list 'iphone', 'ipad'"; - @VisibleForTesting static final String DEVICE_NO_PROVISIONING_PROFILE = "Provisioning profile must be set for device build"; @@ -124,6 +120,7 @@ public final class ReleaseBundlingSupport { private final ObjcProvider objcProvider; private final LinkedBinary linkedBinary; private final IntermediateArtifacts intermediateArtifacts; + private final ReleaseBundling releaseBundling; /** * Indicator as to whether this rule generates a binary directly or whether only dependencies @@ -156,6 +153,8 @@ public final class ReleaseBundlingSupport { * @param bundleMinimumOsVersion the minimum OS version this bundle's plist should be generated * for (<b>not</b> the minimum OS version its binary is compiled with, that needs to be set * through the configuration) + * @param releaseBundling the {@link ReleaseBundling} containing information for creating a + * releaseable bundle. */ ReleaseBundlingSupport( RuleContext ruleContext, @@ -163,13 +162,15 @@ public final class ReleaseBundlingSupport { LinkedBinary linkedBinary, String bundleDirFormat, String bundleName, - DottedVersion bundleMinimumOsVersion) { + DottedVersion bundleMinimumOsVersion, + ReleaseBundling releaseBundling) { this.linkedBinary = linkedBinary; this.attributes = new Attributes(ruleContext); this.ruleContext = ruleContext; this.objcProvider = objcProvider; - this.intermediateArtifacts = ObjcRuleClasses.intermediateArtifacts(ruleContext); - bundling = bundling(ruleContext, objcProvider, bundleDirFormat, bundleName, + this.releaseBundling = releaseBundling; + this.intermediateArtifacts = releaseBundling.getIntermediateArtifacts(); + this.bundling = bundling(ruleContext, objcProvider, bundleDirFormat, bundleName, bundleMinimumOsVersion); bundleSupport = new BundleSupport(ruleContext, bundling, extraActoolArgs()); } @@ -177,6 +178,29 @@ public final class ReleaseBundlingSupport { /** * Creates a new application support within the given rule context. * + * @param ruleContext context for the application-generating rule + * @param objcProvider provider containing all dependencies' information as well as some of this + * rule's + * @param linkedBinary whether to look for a linked binary from this rule and dependencies or just + * the latter + * @param bundleDirFormat format string representing the bundle's directory with a single + * placeholder for the target name (e.g. {@code "Payload/%s.app"}) + * @param bundleName name of the bundle, used with bundleDirFormat + */ + ReleaseBundlingSupport( + RuleContext ruleContext, + ObjcProvider objcProvider, + LinkedBinary linkedBinary, + String bundleDirFormat, + String bundleName, + DottedVersion bundleMinimumOsVersion) throws InterruptedException { + this(ruleContext, objcProvider, linkedBinary, bundleDirFormat, bundleName, + bundleMinimumOsVersion, ReleaseBundling.releaseBundling(ruleContext)); + } + + /** + * Creates a new application support within the given rule context. + * * {@code bundleName} defaults to label name * * @param ruleContext context for the application-generating rule @@ -189,13 +213,14 @@ public final class ReleaseBundlingSupport { * @param bundleMinimumOsVersion the minimum OS version this bundle's plist should be generated * for (<b>not</b> the minimum OS version its binary is compiled with, that needs to be set * through the configuration) + * @throws InterruptedException */ ReleaseBundlingSupport( RuleContext ruleContext, ObjcProvider objcProvider, LinkedBinary linkedBinary, String bundleDirFormat, - DottedVersion bundleMinimumOsVersion) { + DottedVersion bundleMinimumOsVersion) throws InterruptedException { this(ruleContext, objcProvider, linkedBinary, bundleDirFormat, ruleContext.getLabel().getName(), bundleMinimumOsVersion); } @@ -212,30 +237,26 @@ public final class ReleaseBundlingSupport { // 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) { + if (releaseBundling.getAppIcon() != null) { ruleContext.attributeError("app_icon", - String.format(NO_ASSET_CATALOG_ERROR_FORMAT, attributes.appIcon())); + String.format(NO_ASSET_CATALOG_ERROR_FORMAT, releaseBundling.getAppIcon())); } - if (attributes.launchImage() != null) { + if (releaseBundling.getLaunchImage() != null) { ruleContext.attributeError("launch_image", - String.format(NO_ASSET_CATALOG_ERROR_FORMAT, attributes.launchImage())); + String.format(NO_ASSET_CATALOG_ERROR_FORMAT, releaseBundling.getLaunchImage())); } } - if (bundleSupport.targetDeviceFamilies().isEmpty()) { - ruleContext.attributeError("families", INVALID_FAMILIES_ERROR); - } - AppleConfiguration appleConfiguration = ruleContext.getFragment(AppleConfiguration.class); - if (attributes.provisioningProfile() == null + if (releaseBundling.getProvisioningProfile() == null && appleConfiguration.getBundlingPlatform() != Platform.IOS_SIMULATOR) { - ruleContext.attributeError("provisioning_profile", DEVICE_NO_PROVISIONING_PROFILE); + ruleContext.attributeError(releaseBundling.getProvisioningProfileAttrName(), + DEVICE_NO_PROVISIONING_PROFILE); } return this; } - /** * Validates that resources defined in this rule and its dependencies and written to this bundle * are legal. @@ -266,7 +287,7 @@ public final class ReleaseBundlingSupport { registerEnvironmentPlistAction(); registerAutomaticPlistAction(); - if (attributes.launchStoryboard() != null) { + if (releaseBundling.getLaunchStoryboard() != null) { registerLaunchStoryboardPlistAction(); } @@ -315,7 +336,7 @@ public final class ReleaseBundlingSupport { } private void registerLaunchStoryboardPlistAction() { - String launchStoryboard = attributes.launchStoryboard().getFilename(); + String launchStoryboard = releaseBundling.getLaunchStoryboard().getFilename(); String launchStoryboardName = launchStoryboard.substring(0, launchStoryboard.lastIndexOf('.')); NSDictionary result = new NSDictionary(); result.put("UILaunchStoryboardName", launchStoryboardName); @@ -345,7 +366,7 @@ public final class ReleaseBundlingSupport { .addOutput(getGeneratedEnvironmentPlist()) .build(ruleContext)); } - + private void registerAutomaticPlistAction() { ruleContext.registerAction( new FileWriteAction( @@ -392,7 +413,7 @@ public final class ReleaseBundlingSupport { * avoid excessive zipping/unzipping of IPA contents. */ private void registerPostProcessAndSigningActions() throws InterruptedException { - Artifact processedIpa = ruleContext.getImplicitOutputArtifact(IPA); + Artifact processedIpa = releaseBundling.getIpaArtifact(); Artifact unprocessedIpa = intermediateArtifacts.unprocessedIpa(); boolean processingNeeded = false; @@ -422,7 +443,8 @@ public final class ReleaseBundlingSupport { processingNeeded = true; registerEntitlementsActions(); actionCommandLine += signingCommandLine(); - inputs.add(attributes.provisioningProfile()).add(intermediateArtifacts.entitlements()); + inputs.add(releaseBundling.getProvisioningProfile()).add( + intermediateArtifacts.entitlements()); } actionCommandLine += "cd ${t} && /usr/bin/zip -q -r \"${signed_ipa}\" ."; @@ -515,8 +537,8 @@ public final class ReleaseBundlingSupport { NestedSetBuilder.create(Order.STABLE_ORDER, substitutedEntitlements, extraEntitlements), intermediateArtifacts.entitlements()); - Artifact plMergeControlArtifact = - ObjcRuleClasses.artifactByAppendingToBaseName(ruleContext, ".merge-entitlements-control"); + Artifact plMergeControlArtifact = ObjcRuleClasses.artifactByAppendingToBaseName(ruleContext, + artifactName(".merge-entitlements-control")); ruleContext.registerAction( new BinaryFileWriteAction( @@ -569,14 +591,12 @@ public final class ReleaseBundlingSupport { 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)) + filesToBuild.add(releaseBundling.getIpaArtifact()) // TODO(bazel-team): Fat binaries may require some merging of these file rather than just // making them available. .addTransitive(debugSymbolBuilder.build()); @@ -604,8 +624,8 @@ public final class ReleaseBundlingSupport { .build(); // TODO(bazel-team): Handle the FRAMEWORK_DIR key properly. We probably want to add it to // framework search paths, but not actually link it with the -framework flag. - return new XcTestAppProvider(intermediateArtifacts.combinedArchitectureBinary(), - ruleContext.getImplicitOutputArtifact(IPA), partialObjcProvider); + return new XcTestAppProvider(intermediateArtifacts + .combinedArchitectureBinary(), releaseBundling.getIpaArtifact(), partialObjcProvider); } /** @@ -636,9 +656,8 @@ public final class ReleaseBundlingSupport { * Returns a {@link RunfilesSupport} that uses the provided runner script as the executable. */ RunfilesSupport runfilesSupport(Artifact runnerScript) throws InterruptedException { - Artifact ipaFile = ruleContext.getImplicitOutputArtifact(ReleaseBundlingSupport.IPA); Runfiles runfiles = new Runfiles.Builder(ruleContext.getWorkspaceName()) - .addArtifact(ipaFile) + .addArtifact(releaseBundling.getIpaArtifact()) .addArtifact(runnerScript) .addArtifact(attributes.iossim()) .build(); @@ -647,11 +666,11 @@ public final class ReleaseBundlingSupport { private ExtraActoolArgs extraActoolArgs() { ImmutableList.Builder<String> extraArgs = ImmutableList.builder(); - if (attributes.appIcon() != null) { - extraArgs.add("--app-icon", attributes.appIcon()); + if (releaseBundling.getAppIcon() != null) { + extraArgs.add("--app-icon", releaseBundling.getAppIcon()); } - if (attributes.launchImage() != null) { - extraArgs.add("--launch-image", attributes.launchImage()); + if (releaseBundling.getLaunchImage() != null) { + extraArgs.add("--launch-image", releaseBundling.getLaunchImage()); } return new ExtraActoolArgs(extraArgs.build()); } @@ -666,21 +685,11 @@ public final class ReleaseBundlingSupport { 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)); + releaseBundling.getProvisioningProfile(), 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) @@ -689,16 +698,28 @@ public final class ReleaseBundlingSupport { .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 (attributes.launchStoryboard() != null) { + .setIntermediateArtifacts(intermediateArtifacts) + .setPrimaryBundleId(releaseBundling.getPrimaryBundleId()) + .setFallbackBundleId(releaseBundling.getFallbackBundleId()) + .setMinimumOsVersion(minimumOsVersion) + .setArtifactPrefix(releaseBundling.getArtifactPrefix()) + .setTargetDeviceFamilies(releaseBundling.getTargetDeviceFamilies()); + + // Add plists from rule first. + if (releaseBundling.getInfoPlistsFromRule() != null) { + bundling.addInfoplistInputs(releaseBundling.getInfoPlistsFromRule()); + } else { + bundling.addInfoplistInputFromRule(ruleContext); + } + + // Add generated plists next so that generated values can override the default values in the + // plists from rule. + bundling.setAutomaticEntriesInfoplistInput(getGeneratedAutomaticPlist()) + .addInfoplistInput(getGeneratedVersionPlist()) + .addInfoplistInput(getGeneratedEnvironmentPlist()) + .addInfoplistInputs(releaseBundling.getInfoplistInputs()); + + if (releaseBundling.getLaunchStoryboard() != null) { bundling.addInfoplistInput(getLaunchStoryboardPlist()); } @@ -734,16 +755,16 @@ public final class ReleaseBundlingSupport { /** Returns this target's Xcode build settings. */ private Iterable<XcodeprojBuildSetting> buildSettings() { ImmutableList.Builder<XcodeprojBuildSetting> buildSettings = new ImmutableList.Builder<>(); - if (attributes.appIcon() != null) { + if (releaseBundling.getAppIcon() != null) { buildSettings.add(XcodeprojBuildSetting.newBuilder() .setName("ASSETCATALOG_COMPILER_APPICON_NAME") - .setValue(attributes.appIcon()) + .setValue(releaseBundling.getAppIcon()) .build()); } - if (attributes.launchImage() != null) { + if (releaseBundling.getLaunchImage() != null) { buildSettings.add(XcodeprojBuildSetting.newBuilder() .setName("ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME") - .setValue(attributes.launchImage()) + .setValue(releaseBundling.getLaunchImage()) .build()); } @@ -768,8 +789,8 @@ public final class ReleaseBundlingSupport { } private void registerBundleMergeActions() { - Artifact bundleMergeControlArtifact = - ObjcRuleClasses.artifactByAppendingToBaseName(ruleContext, ".ipa-control"); + Artifact bundleMergeControlArtifact = ObjcRuleClasses.artifactByAppendingToBaseName(ruleContext, + artifactName(".ipa-control")); BundleMergeControlBytes controlBytes = new BundleMergeControlBytes( @@ -849,13 +870,13 @@ public final class ReleaseBundlingSupport { private void registerExtractTeamPrefixAction(Artifact teamPrefixFile) { String shellCommand = "set -e && " + "PLIST=$(mktemp -t teamprefix.plist) && trap \"rm ${PLIST}\" EXIT && " - + extractPlistCommand(attributes.provisioningProfile()) + " > ${PLIST} && " + + extractPlistCommand(releaseBundling.getProvisioningProfile()) + " > ${PLIST} && " + "/usr/libexec/PlistBuddy -c 'Print ApplicationIdentifierPrefix:0' ${PLIST} > " + teamPrefixFile.getShellEscapedExecPathString(); ruleContext.registerAction( ObjcRuleClasses.spawnBashOnDarwinActionBuilder(shellCommand) .setMnemonic("ExtractIosTeamPrefix") - .addInput(attributes.provisioningProfile()) + .addInput(releaseBundling.getProvisioningProfile()) .addOutput(teamPrefixFile) .build(ruleContext)); } @@ -868,14 +889,14 @@ public final class ReleaseBundlingSupport { // is the application name, and is specified as an attribute. String shellCommand = "set -e && " + "PLIST=$(mktemp -t entitlements.plist) && trap \"rm ${PLIST}\" EXIT && " - + extractPlistCommand(attributes.provisioningProfile()) + " > ${PLIST} && " + + extractPlistCommand(releaseBundling.getProvisioningProfile()) + " > ${PLIST} && " + "/usr/libexec/PlistBuddy -x -c 'Print Entitlements' ${PLIST} > " + entitlements.getShellEscapedExecPathString(); ruleContext.registerAction( ObjcRuleClasses.spawnBashOnDarwinActionBuilder(shellCommand) .setMnemonic("ExtractIosEntitlements") .setProgressMessage("Extracting entitlements: " + ruleContext.getLabel()) - .addInput(attributes.provisioningProfile()) + .addInput(releaseBundling.getProvisioningProfile()) .addOutput(entitlements) .build(ruleContext)); @@ -884,7 +905,7 @@ public final class ReleaseBundlingSupport { private void registerEntitlementsVariableSubstitutionAction( Artifact inputEntitlements, Artifact prefix, Artifact substitutedEntitlements) { - String escapedBundleId = ShellUtils.shellEscape(attributes.bundleId()); + String escapedBundleId = ShellUtils.shellEscape(releaseBundling.getBundleId()); String shellCommand = "set -e && " + "PREFIX=\"$(cat " @@ -954,7 +975,7 @@ public final class ReleaseBundlingSupport { // configured in it (DeveloperCertificates:0). identity = "$(PLIST=$(mktemp -t cert.plist) && trap \"rm ${PLIST}\" EXIT && " - + extractPlistCommand(attributes.provisioningProfile()) + + extractPlistCommand(releaseBundling.getProvisioningProfile()) + " > ${PLIST} && " + "/usr/libexec/PlistBuddy -c 'Print DeveloperCertificates:0' ${PLIST} | " + "openssl x509 -inform DER -noout -fingerprint | " @@ -970,28 +991,40 @@ public final class ReleaseBundlingSupport { private Artifact getGeneratedVersionPlist() { return ruleContext.getRelatedArtifact( - ruleContext.getUniqueDirectory("plists"), "-version.plist"); + ruleContext.getUniqueDirectory("plists"), artifactName("-version.plist")); } private Artifact getGeneratedEnvironmentPlist() { return ruleContext.getRelatedArtifact( - ruleContext.getUniqueDirectory("plists"), "-environment.plist"); + ruleContext.getUniqueDirectory("plists"), artifactName("-environment.plist")); } - + private Artifact getGeneratedAutomaticPlist() { return ruleContext.getRelatedArtifact( - ruleContext.getUniqueDirectory("plists"), "-automatic.plist"); + ruleContext.getUniqueDirectory("plists"), artifactName("-automatic.plist")); } private Artifact getLaunchStoryboardPlist() { return ruleContext.getRelatedArtifact( - ruleContext.getUniqueDirectory("plists"), "-launchstoryboard.plist"); + ruleContext.getUniqueDirectory("plists"), artifactName("-launchstoryboard.plist")); + } + + /** + * Returns artifact name prefixed with prefix given in {@link ReleaseBundling} if available. + * This helps in creating unique artifact name when multiple bundles are created with a different + * name than the target name. + */ + private String artifactName(String artifactName) { + if (releaseBundling.getArtifactPrefix() != null) { + return String.format("-%s%s", releaseBundling.getArtifactPrefix(), artifactName); + } + return artifactName; } /** - * Logic to access attributes required by application support. Attributes are required and - * guaranteed to return a value or throw unless they are annotated with {@link Nullable} in which - * case they can return {@code null} if no value is defined. + * Logic to access attributes to access tools required by application support. + * Attributes are required and guaranteed to return a value or throw unless they are annotated + * with {@link Nullable} in which case they can return {@code null} if no value is defined. */ private static class Attributes { private final RuleContext ruleContext; @@ -1000,31 +1033,6 @@ public final class ReleaseBundlingSupport { this.ruleContext = ruleContext; } - @Nullable - String appIcon() { - return stringAttribute("app_icon"); - } - - @Nullable - String launchImage() { - return stringAttribute("launch_image"); - } - - @Nullable - Artifact launchStoryboard() { - return ruleContext.getPrerequisiteArtifact("launch_storyboard", Mode.TARGET); - } - - @Nullable - Artifact provisioningProfile() { - Artifact explicitProvisioningProfile = - ruleContext.getPrerequisiteArtifact("provisioning_profile", Mode.TARGET); - if (explicitProvisioningProfile != null) { - return explicitProvisioningProfile; - } - return ruleContext.getPrerequisiteArtifact(":default_provisioning_profile", Mode.TARGET); - } - /** * Returns this target's user-specified {@code ipa_post_processor} or null if not present. */ @@ -1096,10 +1104,6 @@ public final class ReleaseBundlingSupport { return ruleContext.getExecutablePrerequisite("$environment_plist", Mode.HOST); } - String bundleId() { - return checkNotNull(stringAttribute("bundle_id")); - } - ImmutableMap<String, Artifact> cpuSpecificBreakpadFiles() { ImmutableMap.Builder<String, Artifact> results = ImmutableMap.builder(); if (ruleContext.attributes().has("binary", BuildType.LABEL)) { @@ -1119,12 +1123,6 @@ public final class ReleaseBundlingSupport { } return results.build(); } - - @Nullable - private String stringAttribute(String attribute) { - String value = ruleContext.attributes().get(attribute, Type.STRING); - return value.isEmpty() ? null : value; - } } /** |