From 604b7a615ac9af7475e0155abff2ab387e6a1487 Mon Sep 17 00:00:00 2001 From: Peter Schmitt Date: Mon, 21 Mar 2016 18:35:30 +0000 Subject: Allow passing custom entitlements for iOS signing. RELNOTES[NEW]: --extra_entitlements allows passing additional entitlements for iOS signing -- MOS_MIGRATED_REVID=117735783 --- .../build/lib/rules/objc/BundleSupport.java | 4 +- .../lib/rules/objc/ObjcCommandLineOptions.java | 13 +++ .../build/lib/rules/objc/ObjcConfiguration.java | 11 +++ .../build/lib/rules/objc/ObjcRuleClasses.java | 13 +++ .../build/lib/rules/objc/PlMergeControlBytes.java | 96 +++++++++++++++++----- .../lib/rules/objc/ReleaseBundlingSupport.java | 77 +++++++++++++++-- 6 files changed, 184 insertions(+), 30 deletions(-) (limited to 'src') 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 afbfb93c0b..3900c701a0 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 @@ -117,8 +117,8 @@ final class BundleSupport { if (bundling.needsToMergeInfoplist()) { NestedSet mergingContentArtifacts = bundling.getMergingContentArtifacts(); Artifact mergedPlist = bundling.getBundleInfoplist().get(); - PlMergeControlBytes plMergeControlBytes = new PlMergeControlBytes(bundling, mergedPlist); - registerMergeInfoplistAction(mergingContentArtifacts, plMergeControlBytes); + registerMergeInfoplistAction( + mergingContentArtifacts, PlMergeControlBytes.fromBundling(bundling, mergedPlist)); } return this; } diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCommandLineOptions.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCommandLineOptions.java index 9aa540d837..123a7f84da 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCommandLineOptions.java +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCommandLineOptions.java @@ -16,8 +16,10 @@ package com.google.devtools.build.lib.rules.objc; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; +import com.google.devtools.build.lib.analysis.config.BuildConfiguration.LabelConverter; import com.google.devtools.build.lib.analysis.config.BuildOptions; import com.google.devtools.build.lib.analysis.config.FragmentOptions; +import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.packages.Attribute.SplitTransition; import com.google.devtools.build.lib.rules.apple.DottedVersion; import com.google.devtools.build.lib.rules.apple.DottedVersionConverter; @@ -181,6 +183,17 @@ public class ObjcCommandLineOptions extends FragmentOptions { + " GLIBCXX_DEBUG_PEDANTIC and GLIBCPP_CONCEPT_CHECKS." ) public boolean debugWithGlibcxx; + + @Option( + name = "extra_entitlements", + defaultValue = "null", + category = "flags", + converter = LabelConverter.class, + help = + "Location of a .entitlements file that is merged into any iOS signing action in this " + + "build." + ) + public Label extraEntitlements; @VisibleForTesting static final String DEFAULT_MINIMUM_IOS = "7.0"; diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcConfiguration.java index a45dc41b11..6f12170998 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcConfiguration.java +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcConfiguration.java @@ -20,6 +20,7 @@ import com.google.common.collect.ImmutableList; import com.google.devtools.build.lib.analysis.BlazeDirectories; import com.google.devtools.build.lib.analysis.config.BuildConfiguration; import com.google.devtools.build.lib.analysis.config.CompilationMode; +import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; import com.google.devtools.build.lib.rules.apple.DottedVersion; import com.google.devtools.build.lib.rules.objc.ReleaseBundlingSupport.SplitArchTransition.ConfigurationDistinguisher; @@ -69,6 +70,7 @@ public class ObjcConfiguration extends BuildConfiguration.Fragment { private final boolean useAbsolutePathsForActions; private final boolean prioritizeStaticLibs; private final boolean debugWithGlibcxx; + @Nullable private final Label extraEntitlements; ObjcConfiguration(ObjcCommandLineOptions objcOptions, BuildConfiguration.Options options, @Nullable BlazeDirectories directories) { @@ -92,6 +94,7 @@ public class ObjcConfiguration extends BuildConfiguration.Fragment { this.useAbsolutePathsForActions = objcOptions.useAbsolutePathsForActions; this.prioritizeStaticLibs = objcOptions.prioritizeStaticLibs; this.debugWithGlibcxx = objcOptions.debugWithGlibcxx; + this.extraEntitlements = objcOptions.extraEntitlements; } /** @@ -244,4 +247,12 @@ public class ObjcConfiguration extends BuildConfiguration.Fragment { public boolean shouldPrioritizeStaticLibs() { return this.prioritizeStaticLibs; } + + /** + * Returns the extra entitlements plist specified as a flag or {@code null} if none was given. + */ + @Nullable + public Label getExtraEntitlements() { + return extraEntitlements; + } } diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcRuleClasses.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcRuleClasses.java index 461c06d11f..4ffe5589a5 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcRuleClasses.java +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcRuleClasses.java @@ -797,6 +797,19 @@ public class ObjcRuleClasses { $(AppIdentifierPrefix) and $(CFBundleIdentifier). */ .add(attr("entitlements", LABEL).legacyAllowAnyFileType()) + .add( + attr(":extra_entitlements", LABEL) + .singleArtifact() + .value( + new LateBoundLabel(ObjcConfiguration.class) { + @Override + public Label getDefault( + Rule rule, AttributeMap attributes, BuildConfiguration configuration) { + return configuration + .getFragment(ObjcConfiguration.class) + .getExtraEntitlements(); + } + })) /* The provisioning profile (.mobileprovision file) to use when bundling the application. diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/PlMergeControlBytes.java b/src/main/java/com/google/devtools/build/lib/rules/objc/PlMergeControlBytes.java index 4f2e0c15cf..548f6b6d04 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/PlMergeControlBytes.java +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/PlMergeControlBytes.java @@ -14,61 +14,115 @@ package com.google.devtools.build.lib.rules.objc; +import com.google.common.collect.ImmutableMap; import com.google.common.io.ByteSource; import com.google.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.collect.nestedset.NestedSet; +import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; +import com.google.devtools.build.lib.collect.nestedset.Order; import com.google.devtools.build.xcode.plmerge.proto.PlMergeProtos; import com.google.devtools.build.xcode.plmerge.proto.PlMergeProtos.Control; import java.io.IOException; import java.io.InputStream; +import java.util.Map; + +import javax.annotation.Nullable; /** * A byte source that can be used the generate a control file for the tool plmerge. */ public final class PlMergeControlBytes extends ByteSource { - private final Bundling bundling; + private final NestedSet inputPlists; + private final NestedSet immutableInputPlists; + @Nullable private final String primaryBundleId; + @Nullable private final String fallbackBundleId; + @Nullable private final Map variableSubstitutions; + @Nullable private final String executableName; private final Artifact mergedPlist; /** - * @param bundling the {@code Bundling} instance describing the bundle - * for which to create a merged plist - * @param mergedPlist the merged plist that should be bundled as Info.plist + * Creates a control based on the passed bundling's plists and values. + * + * @param bundling bundle for which to create a merged plist + * @param mergedPlist the plist that should be created as an output */ - public PlMergeControlBytes(Bundling bundling, Artifact mergedPlist) { - this.bundling = bundling; + static PlMergeControlBytes fromBundling(Bundling bundling, Artifact mergedPlist) { + + NestedSetBuilder immutableInputPlists = NestedSetBuilder.stableOrder(); + if (bundling.getAutomaticInfoPlist() != null) { + immutableInputPlists.add(bundling.getAutomaticInfoPlist()); + } + + return new PlMergeControlBytes( + NestedSetBuilder.stableOrder() + .addTransitive(bundling.getBundleInfoplistInputs()) + .build(), + immutableInputPlists.build(), + bundling.getPrimaryBundleId(), + bundling.getFallbackBundleId(), + bundling.variableSubstitutions(), + bundling.getName(), + mergedPlist); + } + + /** + * Creates a control that merges the given plists into the merged plist. + */ + static PlMergeControlBytes fromPlists(NestedSet inputPlists, Artifact mergedPlist) { + return new PlMergeControlBytes( + inputPlists, + NestedSetBuilder.emptySet(Order.STABLE_ORDER), + null, + null, + ImmutableMap.of(), + null, + mergedPlist); + } + + private PlMergeControlBytes( + NestedSet inputPlists, + NestedSet immutableInputPlists, + @Nullable String primaryBundleId, + @Nullable String fallbackBundleId, + @Nullable Map variableSubstitutions, + @Nullable String executableName, + Artifact mergedPlist) { + this.inputPlists = inputPlists; + this.immutableInputPlists = immutableInputPlists; + this.primaryBundleId = primaryBundleId; + this.fallbackBundleId = fallbackBundleId; + this.variableSubstitutions = variableSubstitutions; + this.executableName = executableName; this.mergedPlist = mergedPlist; } @Override public InputStream openStream() throws IOException { - return control(bundling).toByteString().newInput(); + return control().toByteString().newInput(); } - private Control control(Bundling bundling) { + private Control control() { PlMergeProtos.Control.Builder control = PlMergeProtos.Control.newBuilder() - .addAllSourceFile(Artifact.toExecPaths(bundling.getBundleInfoplistInputs())) + .addAllSourceFile(Artifact.toExecPaths(inputPlists)) + .addAllImmutableSourceFile(Artifact.toExecPaths(immutableInputPlists)) + .putAllVariableSubstitutionMap(variableSubstitutions) .setOutFile(mergedPlist.getExecPathString()); - if (bundling.getAutomaticInfoPlist() != null) { - control.addImmutableSourceFile(bundling.getAutomaticInfoPlist().getExecPathString()); + if (primaryBundleId != null) { + control.setPrimaryBundleId(primaryBundleId); } - if (bundling.getPrimaryBundleId() != null) { - control.setPrimaryBundleId(bundling.getPrimaryBundleId()); + if (fallbackBundleId != null) { + control.setFallbackBundleId(fallbackBundleId); } - if (bundling.getFallbackBundleId() != null) { - control.setFallbackBundleId(bundling.getFallbackBundleId()); + if (executableName != null) { + control.setExecutableName(executableName); } - if (bundling.variableSubstitutions() != null) { - control.putAllVariableSubstitutionMap(bundling.variableSubstitutions()); - } - - control.setExecutableName(bundling.getName()); - return control.build(); } } 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 795b967369..c6dc2740a8 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 @@ -254,7 +254,6 @@ public final class ReleaseBundlingSupport { * multi-architecture binary. * * @return this application support - * @throws InterruptedException */ ReleaseBundlingSupport registerActions() throws InterruptedException { bundleSupport.registerActions(objcProvider); @@ -467,6 +466,23 @@ public final class ReleaseBundlingSupport { return codesignCommandLineBuilder.toString(); } + /** + * Creates entitlement actions such that an entitlements file is generated in + * {@link IntermediateArtifacts#entitlements()} which can be used for signing in this bundle. + * + *

Entitlements are generated based on a plist-format entitlements file passed to this bundle's + * {@code entitlements} attribute or, if that is not set, entitlements extracted from the provided + * mobile provisioning profile. The team prefix is extracted from the provisioning profile and + * the following substitutions performed (assuming the prefix extracted was {@code PREFIX}): + *

    + *
  1. "PREFIX.*" -> "PREFIX.BUNDLE_ID" (where BUNDLE_ID is this bundle's id) + *
  2. "$(AppIdentifierPrefix)" -> "PREFIX." + *
  3. "$(CFBundleIdentifier)" -> "BUNDLE_ID" (where BUNDLE_ID is this bundle's id) + *
+ * + *

Finally, if an entitlements file was provided via {@code --extra_entitlements} it is merged + * into the substituted entitlements. + */ private void registerEntitlementsActions() throws InterruptedException { Artifact teamPrefixFile = intermediateArtifacts.appendExtensionForEntitlementArtifact(".team_prefix_file"); @@ -479,7 +495,46 @@ public final class ReleaseBundlingSupport { ".entitlements_with_variables"); registerExtractEntitlementsAction(entitlementsNeedingSubstitution); } - registerEntitlementsVariableSubstitutionAction(entitlementsNeedingSubstitution, teamPrefixFile); + + Artifact substitutedEntitlements = intermediateArtifacts.entitlements(); + if (attributes.extraEntitlements() != null) { + substitutedEntitlements = + intermediateArtifacts.appendExtensionForEntitlementArtifact(".substituted"); + registerMergeEntitlementsAction(substitutedEntitlements, attributes.extraEntitlements()); + } + + registerEntitlementsVariableSubstitutionAction( + entitlementsNeedingSubstitution, teamPrefixFile, substitutedEntitlements); + } + + private void registerMergeEntitlementsAction( + Artifact substitutedEntitlements, Artifact extraEntitlements) { + + PlMergeControlBytes controlBytes = + PlMergeControlBytes.fromPlists( + NestedSetBuilder.create(Order.STABLE_ORDER, substitutedEntitlements, extraEntitlements), + intermediateArtifacts.entitlements()); + + Artifact plMergeControlArtifact = + ObjcRuleClasses.artifactByAppendingToBaseName(ruleContext, ".merge-entitlements-control"); + + ruleContext.registerAction( + new BinaryFileWriteAction( + ruleContext.getActionOwner(), + plMergeControlArtifact, + controlBytes, + /*makeExecutable=*/ false)); + + ruleContext.registerAction( + new SpawnAction.Builder() + .setMnemonic("MergeEntitlementsFiles") + .setExecutable(attributes.plmerge()) + .addArgument("--control") + .addInputArgument(plMergeControlArtifact) + .addInput(substitutedEntitlements) + .addInput(extraEntitlements) + .addOutput(intermediateArtifacts.entitlements()) + .build(ruleContext)); } /** @@ -501,7 +556,6 @@ public final class ReleaseBundlingSupport { * top level target in a blaze invocation. * * @return this application support - * @throws InterruptedException */ ReleaseBundlingSupport addFilesToBuild(NestedSetBuilder filesToBuild) throws InterruptedException { @@ -532,7 +586,6 @@ public final class ReleaseBundlingSupport { /** * Creates the {@link XcTestAppProvider} that can be used if this application is used as an * {@code xctest_app}. - * @throws InterruptedException */ XcTestAppProvider xcTestAppProvider() throws InterruptedException { // We want access to #import-able things from our test rig's dependency graph, but we don't @@ -581,7 +634,6 @@ public final class ReleaseBundlingSupport { /** * Returns a {@link RunfilesSupport} that uses the provided runner script as the executable. - * @throws InterruptedException */ RunfilesSupport runfilesSupport(Artifact runnerScript) throws InterruptedException { Artifact ipaFile = ruleContext.getImplicitOutputArtifact(ReleaseBundlingSupport.IPA); @@ -831,8 +883,7 @@ public final class ReleaseBundlingSupport { } private void registerEntitlementsVariableSubstitutionAction( - Artifact inputEntitlements, Artifact prefix) { - Artifact substitutedEntitlements = intermediateArtifacts.entitlements(); + Artifact inputEntitlements, Artifact prefix, Artifact substitutedEntitlements) { String escapedBundleId = ShellUtils.shellEscape(attributes.bundleId()); String shellCommand = "set -e && " @@ -990,6 +1041,11 @@ public final class ReleaseBundlingSupport { return ruleContext.getPrerequisiteArtifact("entitlements", Mode.TARGET); } + @Nullable + Artifact extraEntitlements() { + return ruleContext.getPrerequisiteArtifact(":extra_entitlements", Mode.TARGET); + } + NestedSet dependentLinkedBinaries() { if (ruleContext.attributes().getAttributeDefinition("binary") == null) { return NestedSetBuilder.emptySet(Order.STABLE_ORDER); @@ -1008,6 +1064,13 @@ public final class ReleaseBundlingSupport { return checkNotNull(ruleContext.getExecutablePrerequisite("$bundlemerge", Mode.HOST)); } + /** + * Returns a reference to the plmerge executable. + */ + FilesToRunProvider plmerge() { + return ruleContext.getExecutablePrerequisite("$plmerge", Mode.HOST); + } + Artifact iossim() { return checkNotNull(ruleContext.getPrerequisiteArtifact("$iossim", Mode.HOST)); } -- cgit v1.2.3