aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java3
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/AppleBinary.java10
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/AppleWatch1Extension.java15
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/AppleWatch2Extension.java176
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/AppleWatch2ExtensionRule.java76
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/Bundling.java11
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/IntermediateArtifacts.java9
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/IosApplication.java3
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/IosApplicationRule.java35
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProvider.java14
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/Watch2ExtensionSupport.java236
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/WatchApplicationSupport.java155
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/WatchExtensionSupport.java57
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/WatchUtils.java49
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/XcodeProductType.java4
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/XcodeProvider.java19
16 files changed, 757 insertions, 115 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
index 8fe4241985..403acc7f8e 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
@@ -108,6 +108,7 @@ import com.google.devtools.build.lib.rules.java.ProguardLibraryRule;
import com.google.devtools.build.lib.rules.objc.AppleBinaryRule;
import com.google.devtools.build.lib.rules.objc.AppleSkylarkCommon;
import com.google.devtools.build.lib.rules.objc.AppleWatch1ExtensionRule;
+import com.google.devtools.build.lib.rules.objc.AppleWatch2ExtensionRule;
import com.google.devtools.build.lib.rules.objc.AppleWatchExtensionBinaryRule;
import com.google.devtools.build.lib.rules.objc.BazelJ2ObjcProtoAspect;
import com.google.devtools.build.lib.rules.objc.ExperimentalObjcLibraryRule;
@@ -145,7 +146,6 @@ import com.google.devtools.build.lib.rules.repository.LocalRepositoryRule;
import com.google.devtools.build.lib.rules.repository.NewLocalRepositoryRule;
import com.google.devtools.build.lib.rules.repository.WorkspaceBaseRule;
import com.google.devtools.build.lib.util.ResourceFileLoader;
-
import java.io.IOException;
/**
@@ -456,6 +456,7 @@ public class BazelRuleClassProvider {
builder.addRuleDefinition(new ObjcRuleClasses.WatchApplicationBundleRule());
builder.addRuleDefinition(new ObjcRuleClasses.CrosstoolRule());
builder.addRuleDefinition(new AppleWatch1ExtensionRule());
+ builder.addRuleDefinition(new AppleWatch2ExtensionRule());
builder.addRuleDefinition(new AppleWatchExtensionBinaryRule());
builder.addRuleDefinition(new IosApplicationRule());
builder.addRuleDefinition(new IosExtensionBinaryRule());
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleBinary.java b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleBinary.java
index 77b659ff01..4c878e648d 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleBinary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleBinary.java
@@ -14,6 +14,7 @@
package com.google.devtools.build.lib.rules.objc;
+import static com.google.devtools.build.lib.rules.objc.ObjcProvider.MULTI_ARCH_LINKED_BINARIES;
import static com.google.devtools.build.lib.syntax.Type.STRING;
import com.google.common.annotations.VisibleForTesting;
@@ -44,7 +45,6 @@ import com.google.devtools.build.lib.rules.cpp.CcToolchainProvider;
import com.google.devtools.build.lib.rules.objc.CompilationSupport.ExtraLinkArgs;
import com.google.devtools.build.lib.rules.objc.ObjcCommon.ResourceAttributes;
import com.google.devtools.build.lib.rules.objc.ProtoSupport.TargetType;
-
import java.util.List;
import java.util.Set;
@@ -92,6 +92,8 @@ public class AppleBinary implements RuleConfiguredTargetFactory {
NestedSetBuilder.<Artifact>stableOrder()
.add(ruleIntermediateArtifacts.combinedArchitectureBinary());
+ ObjcProvider.Builder objcProviderBuilder = new ObjcProvider.Builder();
+
for (BuildConfiguration childConfig : childConfigurations) {
IntermediateArtifacts intermediateArtifacts =
ObjcRuleClasses.intermediateArtifacts(ruleContext, childConfig);
@@ -141,6 +143,8 @@ public class AppleBinary implements RuleConfiguredTargetFactory {
DsymOutputType.APP)
.validateAttributes();
ruleContext.assertNoErrors();
+
+ objcProviderBuilder.addTransitiveAndPropagate(common.getObjcProvider());
}
AppleConfiguration appleConfiguration = ruleContext.getFragment(AppleConfiguration.class);
@@ -154,6 +158,10 @@ public class AppleBinary implements RuleConfiguredTargetFactory {
RuleConfiguredTargetBuilder targetBuilder =
ObjcRuleClasses.ruleConfiguredTarget(ruleContext, filesToBuild.build());
+ objcProviderBuilder.add(
+ MULTI_ARCH_LINKED_BINARIES, ruleIntermediateArtifacts.combinedArchitectureBinary());
+
+ targetBuilder.addProvider(ObjcProvider.class, objcProviderBuilder.build());
return targetBuilder.build();
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleWatch1Extension.java b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleWatch1Extension.java
index 6100bf2d74..e43ca738d2 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleWatch1Extension.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleWatch1Extension.java
@@ -31,7 +31,6 @@ import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.analysis.config.BuildOptions;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.packages.Attribute.SplitTransition;
-import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory;
import com.google.devtools.build.lib.rules.apple.AppleConfiguration.ConfigurationDistinguisher;
import com.google.devtools.build.lib.rules.objc.IosExtension.ExtensionSplitArchTransition;
@@ -56,7 +55,6 @@ public class AppleWatch1Extension implements RuleConfiguredTargetFactory {
@Override
public ConfiguredTarget create(RuleContext ruleContext)
throws InterruptedException, RuleErrorException {
- ObjcProvider.Builder applicationObjcProviderBuilder = new ObjcProvider.Builder();
ObjcProvider.Builder extensionObjcProviderBuilder = new ObjcProvider.Builder();
ObjcProvider.Builder exposedObjcProviderBuilder = new ObjcProvider.Builder();
XcodeProvider.Builder applicationXcodeProviderBuilder = new XcodeProvider.Builder();
@@ -68,7 +66,6 @@ public class AppleWatch1Extension implements RuleConfiguredTargetFactory {
createWatchApplicationBundle(
ruleContext,
applicationXcodeProviderBuilder,
- applicationObjcProviderBuilder,
applicationFilesToBuild,
exposedObjcProviderBuilder);
@@ -143,14 +140,12 @@ public class AppleWatch1Extension implements RuleConfiguredTargetFactory {
* Creates a watch application bundle.
* @param ruleContext rule context in which to create the bundle
* @param xcodeProviderBuilder {@link XcodeProvider.Builder} for the application
- * @param objcProviderBuilder {@link ObjcProvider.Builder} for the application
* @param filesToBuild the list to contain the files to be built for this bundle
* @param exposedObjcProviderBuilder {@link ObjcProvider.Builder} exposed to the parent target
*/
private void createWatchApplicationBundle(
RuleContext ruleContext,
XcodeProvider.Builder xcodeProviderBuilder,
- ObjcProvider.Builder objcProviderBuilder,
NestedSetBuilder<Artifact> filesToBuild,
ObjcProvider.Builder exposedObjcProviderBuilder)
throws InterruptedException {
@@ -161,10 +156,12 @@ public class AppleWatch1Extension implements RuleConfiguredTargetFactory {
new IntermediateArtifacts(ruleContext, "", watchApplicationBundleName(ruleContext)),
watchApplicationBundleName(ruleContext),
watchApplicationIpaArtifact(ruleContext),
- watchApplicationBundleName(ruleContext),
- ConfigurationDistinguisher.WATCH_OS1_EXTENSION)
- .createBundle(
- xcodeProviderBuilder, objcProviderBuilder, filesToBuild, exposedObjcProviderBuilder);
+ watchApplicationBundleName(ruleContext))
+ .createBundleAndXcodeproj(
+ xcodeProviderBuilder,
+ ImmutableList.<Artifact>of(),
+ filesToBuild,
+ exposedObjcProviderBuilder);
}
/**
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleWatch2Extension.java b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleWatch2Extension.java
new file mode 100644
index 0000000000..d208062813
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleWatch2Extension.java
@@ -0,0 +1,176 @@
+// 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 static com.google.devtools.build.lib.packages.ImplicitOutputsFunction.fromTemplates;
+import static com.google.devtools.build.lib.rules.objc.ObjcProvider.FLAG;
+import static com.google.devtools.build.lib.rules.objc.ObjcProvider.Flag.HAS_WATCH2_EXTENSION;
+import static com.google.devtools.build.lib.rules.objc.ObjcProvider.MERGE_ZIP;
+import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.WatchApplicationBundleRule.WATCH_APP_NAME_ATTR;
+
+import com.google.common.collect.HashMultiset;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Multiset;
+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;
+import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
+import com.google.devtools.build.lib.analysis.RuleContext;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.packages.ImplicitOutputsFunction.SafeImplicitOutputsFunction;
+import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory;
+import com.google.devtools.build.lib.rules.objc.WatchUtils.WatchOSVersion;
+import com.google.devtools.build.lib.rules.test.InstrumentedFilesCollector;
+import com.google.devtools.build.lib.rules.test.InstrumentedFilesProvider;
+import com.google.devtools.build.lib.syntax.Type;
+
+/** Implementation for {@code apple_watch2_extension}. */
+public class AppleWatch2Extension implements RuleConfiguredTargetFactory {
+
+ /** Template for the containing application folder. */
+ public static final SafeImplicitOutputsFunction APP_NAME_IPA = fromTemplates("%{app_name}.ipa");
+
+ @Override
+ public ConfiguredTarget create(RuleContext ruleContext)
+ throws InterruptedException, RuleErrorException {
+ validateAttributes(ruleContext);
+
+ ObjcProvider.Builder exposedObjcProviderBuilder = new ObjcProvider.Builder();
+ NestedSetBuilder<Artifact> applicationFilesToBuild = NestedSetBuilder.stableOrder();
+
+ // 1. Build watch extension bundle.
+ createWatchExtensionBundle(ruleContext);
+
+ // 2. Build watch application bundle, which will contain the extension bundle.
+ createWatchApplicationBundle(
+ ruleContext,
+ watchExtensionIpaArtifact(ruleContext),
+ applicationFilesToBuild,
+ exposedObjcProviderBuilder);
+
+ RuleConfiguredTargetBuilder targetBuilder =
+ ObjcRuleClasses.ruleConfiguredTarget(ruleContext, applicationFilesToBuild.build())
+ .addProvider(
+ InstrumentedFilesProvider.class,
+ InstrumentedFilesCollector.forward(ruleContext, "binary"));
+
+ // 3. Add final watch application artifacts to the ObjcProvider, for bundling the watch
+ // application bundle into the final iOS application IPA depending on this rule.
+ exposedObjcProviderBuilder.add(MERGE_ZIP, ruleContext.getImplicitOutputArtifact(APP_NAME_IPA));
+ WatchUtils.registerActionsToAddWatchSupport(
+ ruleContext, exposedObjcProviderBuilder, WatchOSVersion.OS2);
+ exposedObjcProviderBuilder.add(FLAG, HAS_WATCH2_EXTENSION);
+ targetBuilder.addProvider(ObjcProvider.class, exposedObjcProviderBuilder.build());
+
+ return targetBuilder.build();
+ }
+
+ /**
+ * Registers actions to create the watch extension bundle.
+ *
+ * @param ruleContext rule context in which to create the bundle
+ */
+ private void createWatchExtensionBundle(RuleContext ruleContext) throws InterruptedException {
+ new Watch2ExtensionSupport(
+ ruleContext,
+ ObjcRuleClasses.intermediateArtifacts(ruleContext),
+ watchExtensionBundleName(ruleContext))
+ .createBundle(watchExtensionIpaArtifact(ruleContext));
+ }
+
+ /**
+ * Registers actions to create the watch application bundle. This will contain the watch extension
+ * bundle. The output artifacts are {@link #APP_NAME_IPA} (which is an implicit output of this
+ * rule), and artifacts which are added to {@code exposedObjcProviderBuilder} for consumption by
+ * depending targets.
+ *
+ * @param ruleContext rule context in which to create the bundle
+ * @param filesToBuild the list to contain the files to be built for this bundle
+ * @param exposedObjcProviderBuilder builder of {@link ObjcProvider} exposed to the parent target;
+ * bundling information will be added to this builder
+ */
+ private void createWatchApplicationBundle(
+ RuleContext ruleContext,
+ Artifact extensionIpa,
+ NestedSetBuilder<Artifact> filesToBuild,
+ ObjcProvider.Builder exposedObjcProviderBuilder)
+ throws InterruptedException {
+ new WatchApplicationSupport(
+ ruleContext,
+ WatchOSVersion.OS2,
+ // TODO(cparsons): Remove dependency attributes from WatchApplicationSupport,
+ // as this is redundant with other attributes.
+ ImmutableSet.<Attribute>of(),
+ new IntermediateArtifacts(ruleContext, "", watchApplicationBundleName(ruleContext)),
+ watchApplicationBundleName(ruleContext),
+ watchApplicationIpaArtifact(ruleContext),
+ watchApplicationBundleName(ruleContext))
+ .createBundle(ImmutableList.of(extensionIpa), filesToBuild, exposedObjcProviderBuilder);
+ }
+
+ /** Returns the {@Artifact} containing final watch application bundle. */
+ private Artifact watchApplicationIpaArtifact(RuleContext ruleContext)
+ throws InterruptedException {
+ return ruleContext.getImplicitOutputArtifact(APP_NAME_IPA);
+ }
+
+ /** Returns the {@Artifact} containing final watch extension bundle. */
+ private Artifact watchExtensionIpaArtifact(RuleContext ruleContext) throws InterruptedException {
+ return ruleContext.getImplicitOutputArtifact(ReleaseBundlingSupport.IPA);
+ }
+
+ private String watchApplicationBundleName(RuleContext ruleContext) {
+ return ruleContext.attributes().get(WATCH_APP_NAME_ATTR, Type.STRING);
+ }
+
+ private String watchExtensionBundleName(RuleContext ruleContext) {
+ return ruleContext.getLabel().getName();
+ }
+
+ private void validateAttributes(RuleContext ruleContext) throws RuleErrorException {
+ boolean hasError = false;
+
+ Multiset<Artifact> appResources = HashMultiset.create();
+ appResources.addAll(ruleContext.getPrerequisiteArtifacts("app_resources", Mode.TARGET).list());
+ appResources.addAll(ruleContext.getPrerequisiteArtifacts("app_strings", Mode.TARGET).list());
+
+ for (Multiset.Entry<Artifact> entry : appResources.entrySet()) {
+ if (entry.getCount() > 1) {
+ ruleContext.ruleError(
+ "The same file was included multiple times in this rule: "
+ + entry.getElement().getRootRelativePathString());
+ hasError = true;
+ }
+ }
+
+ Multiset<Artifact> extResources = HashMultiset.create();
+ extResources.addAll(ruleContext.getPrerequisiteArtifacts("ext_resources", Mode.TARGET).list());
+ extResources.addAll(ruleContext.getPrerequisiteArtifacts("ext_strings", Mode.TARGET).list());
+
+ for (Multiset.Entry<Artifact> entry : extResources.entrySet()) {
+ if (entry.getCount() > 1) {
+ ruleContext.ruleError(
+ "The same file was included multiple times in this rule: "
+ + entry.getElement().getRootRelativePathString());
+ hasError = true;
+ }
+ }
+
+ if (hasError) {
+ throw new RuleErrorException();
+ }
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleWatch2ExtensionRule.java b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleWatch2ExtensionRule.java
new file mode 100644
index 0000000000..2149b4c09e
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleWatch2ExtensionRule.java
@@ -0,0 +1,76 @@
+// 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 static com.google.devtools.build.lib.packages.Attribute.attr;
+import static com.google.devtools.build.lib.packages.BuildType.LABEL;
+
+import com.google.devtools.build.lib.analysis.BaseRuleClasses;
+import com.google.devtools.build.lib.analysis.RuleDefinition;
+import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
+import com.google.devtools.build.lib.packages.RuleClass;
+import com.google.devtools.build.lib.packages.RuleClass.Builder;
+import com.google.devtools.build.lib.rules.apple.AppleConfiguration;
+
+/** Rule definition for apple_watch2_extension. */
+public class AppleWatch2ExtensionRule implements RuleDefinition {
+
+ @Override
+ public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
+ return builder
+ .requiresConfigurationFragments(ObjcConfiguration.class, AppleConfiguration.class)
+ /* <!-- #BLAZE_RULE(apple_watch2_extension).ATTRIBUTE(binary) -->
+ The binary target containing the logic for the watch extension.
+ ${SYNOPSIS}
+ <!-- #END_BLAZE_RULE.ATTRIBUTE -->*/
+ .add(
+ attr("binary", LABEL)
+ .allowedRuleClasses("apple_binary")
+ .allowedFileTypes()
+ .mandatory()
+ .direct_compile_time_input())
+ .build();
+ }
+
+ @Override
+ public Metadata getMetadata() {
+ return RuleDefinition.Metadata.builder()
+ .name("apple_watch2_extension")
+ .factoryClass(AppleWatch2Extension.class)
+ .ancestors(
+ BaseRuleClasses.BaseRule.class,
+ ObjcRuleClasses.XcodegenRule.class,
+ ObjcRuleClasses.WatchApplicationBundleRule.class,
+ ObjcRuleClasses.WatchExtensionBundleRule.class)
+ .build();
+ }
+}
+
+/*<!-- #BLAZE_RULE (NAME = apple_watch2_extension, TYPE = BINARY, FAMILY = Objective-C) -->
+
+<p>This rule produces an extension bundle for apple watch OS 2.</p>
+
+<p>It requires attributes set for both the watchOS2 application and watchOS2 extension that will be
+ present in any final ios application bundle. Application attributes are prefixed with app_, and
+ extension attributes prefixed with ext_.</p>
+
+<p>The required 'binary' attribute should contain the apple_binary extension binary (built for
+ the watch platform type.</p>
+
+${IMPLICIT_OUTPUTS}
+
+${ATTRIBUTE_DEFINITION}
+
+<!-- #END_BLAZE_RULE -->*/
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 e00d64bf8d..3bbb1eb901 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
@@ -21,6 +21,7 @@ import static com.google.devtools.build.lib.rules.objc.ObjcProvider.Flag.USES_SW
import static com.google.devtools.build.lib.rules.objc.ObjcProvider.IMPORTED_LIBRARY;
import static com.google.devtools.build.lib.rules.objc.ObjcProvider.LIBRARY;
import static com.google.devtools.build.lib.rules.objc.ObjcProvider.MERGE_ZIP;
+import static com.google.devtools.build.lib.rules.objc.ObjcProvider.MULTI_ARCH_LINKED_BINARIES;
import static com.google.devtools.build.lib.rules.objc.ObjcProvider.NESTED_BUNDLE;
import static com.google.devtools.build.lib.rules.objc.ObjcProvider.ROOT_MERGE_ZIP;
import static com.google.devtools.build.lib.rules.objc.ObjcProvider.STORYBOARD;
@@ -249,13 +250,13 @@ final class Bundling {
}
private Optional<Artifact> combinedArchitectureBinary() {
- Optional<Artifact> combinedArchitectureBinary = Optional.absent();
- if (!Iterables.isEmpty(objcProvider.get(LIBRARY))
+ if (!Iterables.isEmpty(objcProvider.get(MULTI_ARCH_LINKED_BINARIES))) {
+ return Optional.of(Iterables.getOnlyElement(objcProvider.get(MULTI_ARCH_LINKED_BINARIES)));
+ } else if (!Iterables.isEmpty(objcProvider.get(LIBRARY))
|| !Iterables.isEmpty(objcProvider.get(IMPORTED_LIBRARY))) {
- combinedArchitectureBinary =
- Optional.of(intermediateArtifacts.combinedArchitectureBinary());
+ return Optional.of(intermediateArtifacts.combinedArchitectureBinary());
}
- return combinedArchitectureBinary;
+ return Optional.absent();
}
private Optional<Artifact> actoolzipOutput() {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/IntermediateArtifacts.java b/src/main/java/com/google/devtools/build/lib/rules/objc/IntermediateArtifacts.java
index 0ccc9d2752..455526a393 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/IntermediateArtifacts.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/IntermediateArtifacts.java
@@ -86,6 +86,15 @@ public final class IntermediateArtifacts {
}
/**
+ * Returns the location of this target's extension plist which contains entries required by all
+ * watch extensions (for final merging into the bundle plist).
+ */
+ public Artifact watchExtensionAutomaticPlist() {
+ return ruleContext.getRelatedArtifact(
+ ruleContext.getUniqueDirectory("plists"), "-automatic-watchExtensionInfo.plist");
+ }
+
+ /**
* Returns a derived artifact in the bin directory obtained by appending some extension to the end
* of the given {@link PathFragment}.
*/
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/IosApplication.java b/src/main/java/com/google/devtools/build/lib/rules/objc/IosApplication.java
index 617fd3ece9..506c5088d4 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/IosApplication.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/IosApplication.java
@@ -61,7 +61,8 @@ public class IosApplication extends ReleaseBundlingTargetFactory {
protected void validateAttributes(RuleContext ruleContext) {
Iterable<ObjcProvider> extensionProviders = ruleContext.getPrerequisites(
"extensions", Mode.TARGET, ObjcProvider.class);
- if (hasMoreThanOneWatchExtension(extensionProviders, Flag.HAS_WATCH1_EXTENSION)) {
+ if (hasMoreThanOneWatchExtension(extensionProviders, Flag.HAS_WATCH1_EXTENSION)
+ || hasMoreThanOneWatchExtension(extensionProviders, Flag.HAS_WATCH2_EXTENSION)) {
ruleContext.attributeError("extensions", "An iOS application can contain exactly one "
+ "watch extension for each watch OS version");
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/IosApplicationRule.java b/src/main/java/com/google/devtools/build/lib/rules/objc/IosApplicationRule.java
index c7a0a2bb26..e299f3aacf 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/IosApplicationRule.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/IosApplicationRule.java
@@ -51,23 +51,30 @@ public class IosApplicationRule implements RuleDefinition {
/* <!-- #BLAZE_RULE(ios_application).ATTRIBUTE(binary) -->
The binary target included in the final bundle.
<!-- #END_BLAZE_RULE.ATTRIBUTE -->*/
- .add(attr("binary", LABEL)
- .allowedRuleClasses("objc_binary")
- .allowedFileTypes()
- .mandatory()
- .direct_compile_time_input()
- .cfg(IosApplication.SPLIT_ARCH_TRANSITION))
+ .add(
+ attr("binary", LABEL)
+ .allowedRuleClasses("objc_binary")
+ .allowedFileTypes()
+ .mandatory()
+ .direct_compile_time_input()
+ .cfg(IosApplication.SPLIT_ARCH_TRANSITION))
/* <!-- #BLAZE_RULE(ios_application).ATTRIBUTE(extensions) -->
Any extensions to include in the final application.
<!-- #END_BLAZE_RULE.ATTRIBUTE -->*/
- .add(attr("extensions", LABEL_LIST)
- .allowedRuleClasses("ios_extension", "apple_watch1_extension")
- .allowedFileTypes()
- .direct_compile_time_input())
- .add(attr("$runner_script_template", LABEL).cfg(HOST)
- .value(env.getToolsLabel("//tools/objc:ios_runner.sh.mac_template")))
- .add(attr("$is_executable", BOOLEAN).value(true)
- .nonconfigurable("Called from RunCommand.isExecutable, which takes a Target"))
+ .add(
+ attr("extensions", LABEL_LIST)
+ .allowedRuleClasses(
+ "ios_extension", "apple_watch1_extension", "apple_watch2_extension")
+ .allowedFileTypes()
+ .direct_compile_time_input())
+ .add(
+ attr("$runner_script_template", LABEL)
+ .cfg(HOST)
+ .value(env.getToolsLabel("//tools/objc:ios_runner.sh.mac_template")))
+ .add(
+ attr("$is_executable", BOOLEAN)
+ .value(true)
+ .nonconfigurable("Called from RunCommand.isExecutable, which takes a Target"))
.build();
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProvider.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProvider.java
index 067d2acb8f..63ad021223 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProvider.java
@@ -35,7 +35,6 @@ import com.google.devtools.build.lib.syntax.EvalUtils;
import com.google.devtools.build.lib.util.Preconditions;
import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.devtools.build.xcode.xcodegen.proto.XcodeGenProtos.TargetControl;
-
import java.util.HashMap;
import java.util.Map;
@@ -106,6 +105,10 @@ public final class ObjcProvider extends SkylarkClassObject implements Transitive
public static final Key<Artifact> LINKED_BINARY =
new Key<>(STABLE_ORDER, "linked_binary", Artifact.class);
+ /** Combined-architecture binaries to include in the final bundle. */
+ public static final Key<Artifact> MULTI_ARCH_LINKED_BINARIES =
+ new Key<>(STABLE_ORDER, "combined_arch_linked_binary", Artifact.class);
+
/**
* Indicates which libraries to load with {@code -force_load}. This is a subset of the union of
* the {@link #LIBRARY} and {@link #IMPORTED_LIBRARY} sets.
@@ -343,9 +346,16 @@ public final class ObjcProvider extends SkylarkClassObject implements Transitive
USES_SWIFT,
/**
- * Indicates that watch os 1 extension is present in the bundle.
+ * Indicates that a watchOS 1 extension is present in the bundle. (There can only be one
+ * extension for any given watchOS version in a given bundle).
*/
HAS_WATCH1_EXTENSION,
+
+ /**
+ * Indicates that a watchOS 2 extension is present in the bundle. (There can only be one
+ * extension for any given watchOS version in a given bundle).
+ */
+ HAS_WATCH2_EXTENSION,
}
private final ImmutableMap<Key<?>, NestedSet<?>> items;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/Watch2ExtensionSupport.java b/src/main/java/com/google/devtools/build/lib/rules/objc/Watch2ExtensionSupport.java
new file mode 100644
index 0000000000..4a0b24ae21
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/Watch2ExtensionSupport.java
@@ -0,0 +1,236 @@
+// 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 static com.google.devtools.build.lib.rules.objc.ObjcProvider.BUNDLE_FILE;
+import static com.google.devtools.build.lib.rules.objc.ObjcProvider.GENERAL_RESOURCE_DIR;
+import static com.google.devtools.build.lib.rules.objc.ObjcProvider.GENERAL_RESOURCE_FILE;
+import static com.google.devtools.build.lib.rules.objc.ObjcProvider.STRINGS;
+import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.BundlingRule.FAMILIES_ATTR;
+import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.WatchExtensionBundleRule.WATCH_EXT_BUNDLE_ID_ATTR;
+import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.WatchExtensionBundleRule.WATCH_EXT_DEFAULT_PROVISIONING_PROFILE_ATTR;
+import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.WatchExtensionBundleRule.WATCH_EXT_ENTITLEMENTS_ATTR;
+import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.WatchExtensionBundleRule.WATCH_EXT_FAMILIES_ATTR;
+import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.WatchExtensionBundleRule.WATCH_EXT_INFOPLISTS_ATTR;
+import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.WatchExtensionBundleRule.WATCH_EXT_PROVISIONING_PROFILE_ATTR;
+import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.WatchExtensionBundleRule.WATCH_EXT_RESOURCES_ATTR;
+import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.WatchExtensionBundleRule.WATCH_EXT_STRINGS_ATTR;
+import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.WatchExtensionBundleRule.WATCH_EXT_STRUCTURED_RESOURCES_ATTR;
+
+import com.dd.plist.NSDictionary;
+import com.dd.plist.NSObject;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+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.analysis.actions.FileWriteAction;
+import com.google.devtools.build.lib.rules.objc.ReleaseBundlingSupport.LinkedBinary;
+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;
+import javax.annotation.Nullable;
+
+/**
+ * Contains support methods to build watch extension bundle - does normal bundle processing -
+ * compiling and linking the binary, resources, plists and creates a final (signed if necessary)
+ * bundle.
+ */
+public class Watch2ExtensionSupport {
+
+ private final RuleContext ruleContext;
+ private final IntermediateArtifacts intermediateArtifacts;
+ private final String bundleName;
+ private final Attributes attributes;
+
+ /**
+ * @param ruleContext the current rule context
+ * @param intermediateArtifacts the utility object to obtain namespacing for intermediate bundling
+ * artifacts
+ * @param bundleName the name of the bundle
+ */
+ Watch2ExtensionSupport(
+ RuleContext ruleContext, IntermediateArtifacts intermediateArtifacts, String bundleName) {
+ this.ruleContext = ruleContext;
+ this.intermediateArtifacts = intermediateArtifacts;
+ this.bundleName = bundleName;
+ this.attributes = new Attributes(ruleContext);
+ }
+
+ /**
+ * Registers actions to create a watchOS2 extension bundle and zip it into an {@code .ipa}.
+ *
+ * @param ipaArtifact an .ipa artifact containing to extension bundle; this is the output artifact
+ * of the bundling
+ */
+ void createBundle(Artifact ipaArtifact) throws InterruptedException {
+ ObjcProvider.Builder releaseBundlingObjcProviderBuilder = new ObjcProvider.Builder();
+ releaseBundlingObjcProviderBuilder.addTransitiveAndPropagate(attributes.binaryDependencies());
+ releaseBundlingObjcProviderBuilder
+ .addAll(GENERAL_RESOURCE_FILE, attributes.resources())
+ .addAll(GENERAL_RESOURCE_FILE, attributes.strings())
+ .addAll(
+ GENERAL_RESOURCE_DIR,
+ ObjcCommon.xcodeStructuredResourceDirs(attributes.structuredResources()))
+ .addAll(BUNDLE_FILE, BundleableFile.flattenedRawResourceFiles(attributes.resources()))
+ .addAll(
+ BUNDLE_FILE,
+ BundleableFile.structuredRawResourceFiles(attributes.structuredResources()))
+ .addAll(STRINGS, attributes.strings());
+ ObjcProvider releaseBundlingObjcProvider = releaseBundlingObjcProviderBuilder.build();
+
+ registerWatchExtensionAutomaticPlistAction();
+
+ ImmutableSet<TargetDeviceFamily> families = attributes.families();
+
+ if (families.isEmpty()) {
+ ruleContext.attributeError(FAMILIES_ATTR, ReleaseBundling.INVALID_FAMILIES_ERROR);
+ }
+
+ ReleaseBundling.Builder releaseBundling =
+ new ReleaseBundling.Builder()
+ .setIpaArtifact(ipaArtifact)
+ .setBundleId(attributes.bundleId())
+ .setProvisioningProfile(attributes.provisioningProfile())
+ .setProvisioningProfileAttributeName(WATCH_EXT_PROVISIONING_PROFILE_ATTR)
+ .setTargetDeviceFamilies(families)
+ .setIntermediateArtifacts(intermediateArtifacts)
+ .setInfoPlistsFromRule(attributes.infoPlists())
+ .addInfoplistInput(intermediateArtifacts.watchExtensionAutomaticPlist())
+ .setEntitlements(attributes.entitlements());
+
+ if (attributes.isBundleIdExplicitySpecified()) {
+ releaseBundling.setPrimaryBundleId(attributes.bundleId());
+ } else {
+ releaseBundling.setFallbackBundleId(attributes.bundleId());
+ }
+
+ ReleaseBundlingSupport releaseBundlingSupport =
+ new ReleaseBundlingSupport(
+ ruleContext,
+ releaseBundlingObjcProvider,
+ LinkedBinary.DEPENDENCIES_ONLY,
+ ReleaseBundlingSupport.EXTENSION_BUNDLE_DIR_FORMAT,
+ bundleName,
+ WatchUtils.determineMinimumOsVersion(
+ ObjcRuleClasses.objcConfiguration(ruleContext).getMinimumOs()),
+ releaseBundling.build());
+
+ releaseBundlingSupport
+ .registerActions(DsymOutputType.APP)
+ .validateResources()
+ .validateAttributes();
+ }
+
+ /**
+ * Registers an action to generate a plist containing entries required for watch extension that
+ * should be added to the merged plist.
+ */
+ private void registerWatchExtensionAutomaticPlistAction() {
+ NSDictionary watchExtensionAutomaticEntries = new NSDictionary();
+ watchExtensionAutomaticEntries.put(
+ "UIRequiredDeviceCapabilities", NSObject.wrap(new String[] {"watch-companion"}));
+
+ ruleContext.registerAction(
+ new FileWriteAction(
+ ruleContext.getActionOwner(),
+ intermediateArtifacts.watchExtensionAutomaticPlist(),
+ watchExtensionAutomaticEntries.toGnuStepASCIIPropertyList(),
+ /*makeExecutable=*/ false));
+ }
+
+ /** Rule attributes used for creating watch application bundle. */
+ private static class Attributes {
+ private final RuleContext ruleContext;
+
+ private Attributes(RuleContext ruleContext) {
+ this.ruleContext = ruleContext;
+ }
+
+ /**
+ * 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(WATCH_EXT_FAMILIES_ATTR, Type.STRING_LIST);
+ try {
+ return ImmutableSet.copyOf(TargetDeviceFamily.fromNamesInRule(rawFamilies));
+ } catch (InvalidFamilyNameException | RepeatedFamilyNameException e) {
+ return ImmutableSet.of();
+ }
+ }
+
+ @Nullable
+ Artifact provisioningProfile() {
+ Artifact explicitProvisioningProfile =
+ getPrerequisiteArtifact(WATCH_EXT_PROVISIONING_PROFILE_ATTR);
+ if (explicitProvisioningProfile != null) {
+ return explicitProvisioningProfile;
+ }
+ return getPrerequisiteArtifact(WATCH_EXT_DEFAULT_PROVISIONING_PROFILE_ATTR);
+ }
+
+ String bundleId() {
+ Preconditions.checkState(
+ !Strings.isNullOrEmpty(
+ ruleContext.attributes().get(WATCH_EXT_BUNDLE_ID_ATTR, Type.STRING)),
+ "requires a bundle_id value");
+ return ruleContext.attributes().get(WATCH_EXT_BUNDLE_ID_ATTR, Type.STRING);
+ }
+
+ ImmutableList<Artifact> infoPlists() {
+ return getPrerequisiteArtifacts(WATCH_EXT_INFOPLISTS_ATTR);
+ }
+
+ ImmutableList<Artifact> strings() {
+ return getPrerequisiteArtifacts(WATCH_EXT_STRINGS_ATTR);
+ }
+
+ ImmutableList<Artifact> resources() {
+ return getPrerequisiteArtifacts(WATCH_EXT_RESOURCES_ATTR);
+ }
+
+ ImmutableList<Artifact> structuredResources() {
+ return getPrerequisiteArtifacts(WATCH_EXT_STRUCTURED_RESOURCES_ATTR);
+ }
+
+ Iterable<ObjcProvider> binaryDependencies() {
+ return ruleContext.getPrerequisites("binary", Mode.TARGET, ObjcProvider.class);
+ }
+
+ @Nullable
+ Artifact entitlements() {
+ return getPrerequisiteArtifact(WATCH_EXT_ENTITLEMENTS_ATTR);
+ }
+
+ private boolean isBundleIdExplicitySpecified() {
+ return ruleContext.attributes().isAttributeValueExplicitlySpecified(WATCH_EXT_BUNDLE_ID_ATTR);
+ }
+
+ private ImmutableList<Artifact> getPrerequisiteArtifacts(String attribute) {
+ return ruleContext.getPrerequisiteArtifacts(attribute, Mode.TARGET).list();
+ }
+
+ @Nullable
+ private Artifact getPrerequisiteArtifact(String attribute) {
+ return ruleContext.getPrerequisiteArtifact(attribute, Mode.TARGET);
+ }
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/WatchApplicationSupport.java b/src/main/java/com/google/devtools/build/lib/rules/objc/WatchApplicationSupport.java
index ad0d1912c8..2a5bd462dc 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/WatchApplicationSupport.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/WatchApplicationSupport.java
@@ -18,6 +18,7 @@ import static com.google.devtools.build.lib.rules.objc.ObjcProvider.ASSET_CATALO
import static com.google.devtools.build.lib.rules.objc.ObjcProvider.BUNDLE_FILE;
import static com.google.devtools.build.lib.rules.objc.ObjcProvider.GENERAL_RESOURCE_DIR;
import static com.google.devtools.build.lib.rules.objc.ObjcProvider.GENERAL_RESOURCE_FILE;
+import static com.google.devtools.build.lib.rules.objc.ObjcProvider.MERGE_ZIP;
import static com.google.devtools.build.lib.rules.objc.ObjcProvider.STORYBOARD;
import static com.google.devtools.build.lib.rules.objc.ObjcProvider.STRINGS;
import static com.google.devtools.build.lib.rules.objc.ObjcProvider.XCASSETS_DIR;
@@ -34,6 +35,7 @@ import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.WatchAppl
import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.WatchApplicationBundleRule.WATCH_APP_STRUCTURED_RESOURCES_ATTR;
import com.google.common.base.Joiner;
+import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
@@ -52,7 +54,6 @@ import com.google.devtools.build.lib.rules.objc.ReleaseBundlingSupport.LinkedBin
import com.google.devtools.build.lib.rules.objc.WatchUtils.WatchOSVersion;
import com.google.devtools.build.lib.syntax.Type;
import com.google.devtools.build.xcode.xcodegen.proto.XcodeGenProtos.XcodeprojBuildSetting;
-
import javax.annotation.Nullable;
/**
@@ -69,12 +70,28 @@ final class WatchApplicationSupport {
private final Attributes attributes;
private final Artifact ipaArtifact;
private final String artifactPrefix;
- private final ConfigurationDistinguisher configurationDistinguisher;
- WatchApplicationSupport(RuleContext ruleContext, WatchOSVersion watchOSVersion,
- ImmutableSet<Attribute> dependencyAttributes, IntermediateArtifacts intermediateArtifacts,
- String bundleName, Artifact ipaArtifact, String artifactPrefix,
- ConfigurationDistinguisher configurationDistinguisher) {
+ /**
+ * @param ruleContext the current rule context
+ * @param watchOSVersion the version of watchOS for which to create an application bundle
+ * @param dependencyAttributes attributes on the current rule context to obtain transitive
+ * resources from
+ * @param intermediateArtifacts the utility object to obtain namespacing for intermediate bundling
+ * artifacts
+ * @param bundleName the name of the bundle
+ * @param ipaArtifact the output ipa created by this application bundling
+ * @param artifactPrefix the string prefix to prepend to bundling artifacts for the application --
+ * this prevents intermediate artifacts under this same rule context (such as watch extension
+ * bundling) from conflicting
+ */
+ WatchApplicationSupport(
+ RuleContext ruleContext,
+ WatchOSVersion watchOSVersion,
+ ImmutableSet<Attribute> dependencyAttributes,
+ IntermediateArtifacts intermediateArtifacts,
+ String bundleName,
+ Artifact ipaArtifact,
+ String artifactPrefix) {
this.ruleContext = ruleContext;
this.watchOSVersion = watchOSVersion;
this.dependencyAttributes = dependencyAttributes;
@@ -83,24 +100,82 @@ final class WatchApplicationSupport {
this.ipaArtifact = ipaArtifact;
this.artifactPrefix = artifactPrefix;
this.attributes = new Attributes(ruleContext);
- this.configurationDistinguisher = configurationDistinguisher;
}
+ /**
+ * Registers actions to create a watch application bundle.
+ *
+ * @param innerBundleZips any zip files to be unzipped and merged into the application bundle
+ * @param filesToBuild files to build for the rule; the watchOS application .ipa is added to this
+ * set
+ * @param exposedObjcProviderBuilder provider builder which watch application bundle outputs are
+ * added to (for later consumption by depending rules)
+ */
void createBundle(
+ Iterable<Artifact> innerBundleZips,
+ NestedSetBuilder<Artifact> filesToBuild,
+ ObjcProvider.Builder exposedObjcProviderBuilder)
+ throws InterruptedException {
+
+ ObjcProvider objcProvider = objcProvider(innerBundleZips);
+
+ createBundle(
+ Optional.<XcodeProvider.Builder>absent(),
+ objcProvider,
+ filesToBuild,
+ exposedObjcProviderBuilder);
+ }
+
+ /**
+ * Registers actions to create a watch application bundle and xcode project.
+ *
+ * @param xcodeProviderBuilder provider builder which xcode project generation information is
+ * added to (for later consumption by depending rules)
+ * @param innerBundleZips any zip files to be unzipped and merged into the application bundle
+ * @param filesToBuild files to build for the rule; the watchOS application .ipa is added to this
+ * set
+ * @param exposedObjcProviderBuilder provider builder which watch application bundle outputs are
+ * added to (for later consumption by depending rules)
+ */
+ void createBundleAndXcodeproj(
XcodeProvider.Builder xcodeProviderBuilder,
- ObjcProvider.Builder objcProviderBuilder,
+ Iterable<Artifact> innerBundleZips,
NestedSetBuilder<Artifact> filesToBuild,
ObjcProvider.Builder exposedObjcProviderBuilder)
throws InterruptedException {
+ ObjcProvider objcProvider = objcProvider(innerBundleZips);
+
+ createBundle(
+ Optional.of(xcodeProviderBuilder), objcProvider, filesToBuild, exposedObjcProviderBuilder);
+
// Add common watch settings.
WatchUtils.addXcodeSettings(ruleContext, xcodeProviderBuilder);
// Add watch application specific xcode settings.
addXcodeSettings(xcodeProviderBuilder);
+ XcodeSupport xcodeSupport =
+ new XcodeSupport(ruleContext, intermediateArtifacts, labelForWatchApplication())
+ .addXcodeSettings(
+ xcodeProviderBuilder,
+ objcProvider,
+ watchOSVersion.getApplicationXcodeProductType(),
+ ruleContext.getFragment(AppleConfiguration.class).getIosCpu(),
+ ConfigurationDistinguisher.WATCH_OS1_EXTENSION);
+
+ for (Attribute attribute : dependencyAttributes) {
+ xcodeSupport.addDependencies(xcodeProviderBuilder, attribute);
+ }
+ }
+
+ private void createBundle(
+ Optional<XcodeProvider.Builder> xcodeProviderBuilder,
+ ObjcProvider depsObjcProvider,
+ NestedSetBuilder<Artifact> filesToBuild,
+ ObjcProvider.Builder exposedObjcProviderBuilder)
+ throws InterruptedException {
registerActions();
- ObjcProvider objcProvider = objcProvider(objcProviderBuilder);
ReleaseBundling.Builder releaseBundling = new ReleaseBundling.Builder()
.setIpaArtifact(ipaArtifact)
.setBundleId(attributes.bundleId())
@@ -119,32 +194,27 @@ final class WatchApplicationSupport {
releaseBundling.setFallbackBundleId(attributes.bundleId());
}
- new ReleaseBundlingSupport(
- ruleContext,
- objcProvider,
- LinkedBinary.DEPENDENCIES_ONLY,
- ReleaseBundlingSupport.APP_BUNDLE_DIR_FORMAT,
- bundleName,
- WatchUtils.determineMinimumOsVersion(
- ObjcRuleClasses.objcConfiguration(ruleContext).getMinimumOs()),
- releaseBundling.build())
- .registerActions(DsymOutputType.APP)
- .addXcodeSettings(xcodeProviderBuilder)
+ ReleaseBundlingSupport releaseBundlingSupport =
+ new ReleaseBundlingSupport(
+ ruleContext,
+ depsObjcProvider,
+ LinkedBinary.DEPENDENCIES_ONLY,
+ watchOSVersion.getApplicationBundleDirFormat(),
+ bundleName,
+ WatchUtils.determineMinimumOsVersion(
+ ObjcRuleClasses.objcConfiguration(ruleContext).getMinimumOs()),
+ releaseBundling.build())
+ .registerActions(DsymOutputType.APP);
+
+ if (xcodeProviderBuilder.isPresent()) {
+ releaseBundlingSupport.addXcodeSettings(xcodeProviderBuilder.get());
+ }
+
+ releaseBundlingSupport
.addFilesToBuild(filesToBuild, DsymOutputType.APP)
.validateResources()
.validateAttributes()
.addExportedDebugArtifacts(exposedObjcProviderBuilder, DsymOutputType.APP);
-
- XcodeSupport xcodeSupport = new XcodeSupport(ruleContext, intermediateArtifacts,
- labelForWatchApplication())
- .addXcodeSettings(xcodeProviderBuilder, objcProvider,
- watchOSVersion.getApplicationXcodeProductType(),
- ruleContext.getFragment(AppleConfiguration.class).getIosCpu(),
- configurationDistinguisher);
-
- for (Attribute attribute : dependencyAttributes) {
- xcodeSupport.addDependencies(xcodeProviderBuilder, attribute);
- }
}
/**
@@ -208,16 +278,23 @@ final class WatchApplicationSupport {
watchKitStubZip.getFilename(),
Joiner.on(" ").join(ImmutableList.of("_WatchKitStub", bundleName))));
- ruleContext.registerAction(ObjcRuleClasses.spawnAppleEnvActionBuilder(ruleContext,
- ruleContext.getFragment(AppleConfiguration.class).getMultiArchPlatform(PlatformType.IOS))
- .setProgressMessage(
- "Copying WatchKit binary and stub resource: " + ruleContext.getLabel())
- .setShellCommand(ImmutableList.of("/bin/bash", "-c", Joiner.on(" ").join(command)))
- .addOutput(watchKitStubZip)
- .build(ruleContext));
+ ruleContext.registerAction(
+ ObjcRuleClasses.spawnAppleEnvActionBuilder(
+ ruleContext,
+ ruleContext
+ .getFragment(AppleConfiguration.class)
+ .getMultiArchPlatform(PlatformType.WATCHOS))
+ .setProgressMessage(
+ "Copying WatchKit binary and stub resource: " + ruleContext.getLabel())
+ .setShellCommand(ImmutableList.of("/bin/bash", "-c", Joiner.on(" ").join(command)))
+ .addOutput(watchKitStubZip)
+ .build(ruleContext));
}
- private ObjcProvider objcProvider(ObjcProvider.Builder objcProviderBuilder) {
+ private ObjcProvider objcProvider(Iterable<Artifact> innerBundleZips) {
+ ObjcProvider.Builder objcProviderBuilder = new ObjcProvider.Builder();
+ objcProviderBuilder.addAll(MERGE_ZIP, innerBundleZips);
+
// Add all resource files applicable to watch application from dependency providers.
for (Attribute attribute : dependencyAttributes) {
Iterable<ObjcProvider> dependencyObjcProviders = ruleContext.getPrerequisites(
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/WatchExtensionSupport.java b/src/main/java/com/google/devtools/build/lib/rules/objc/WatchExtensionSupport.java
index bed207d76f..ce070131d7 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/WatchExtensionSupport.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/WatchExtensionSupport.java
@@ -31,6 +31,8 @@ import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.WatchExte
import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.WatchExtensionBundleRule.WATCH_EXT_STRINGS_ATTR;
import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.WatchExtensionBundleRule.WATCH_EXT_STRUCTURED_RESOURCES_ATTR;
+import com.dd.plist.NSDictionary;
+import com.dd.plist.NSObject;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
@@ -48,12 +50,7 @@ import com.google.devtools.build.lib.rules.objc.TargetDeviceFamily.InvalidFamily
import com.google.devtools.build.lib.rules.objc.TargetDeviceFamily.RepeatedFamilyNameException;
import com.google.devtools.build.lib.rules.objc.WatchUtils.WatchOSVersion;
import com.google.devtools.build.lib.syntax.Type;
-
-import com.dd.plist.NSDictionary;
-import com.dd.plist.NSObject;
-
import java.util.List;
-
import javax.annotation.Nullable;
/**
@@ -74,14 +71,15 @@ public class WatchExtensionSupport {
private final XcodeProvider watchApplicationXcodeProvider;
private final ConfigurationDistinguisher configurationDistinguisher;
- WatchExtensionSupport(RuleContext ruleContext,
+ WatchExtensionSupport(
+ RuleContext ruleContext,
WatchOSVersion watchOSVersion,
ImmutableSet<Attribute> dependencyAttributes,
IntermediateArtifacts intermediateArtifacts,
String bundleName,
Artifact ipaArtifact,
- Artifact watchApplicationBundle,
- XcodeProvider watchApplicationXcodeProvider,
+ @Nullable Artifact watchApplicationBundle,
+ @Nullable XcodeProvider watchApplicationXcodeProvider,
ConfigurationDistinguisher configurationDistinguisher) {
this.ruleContext = ruleContext;
this.watchOSVersion = watchOSVersion;
@@ -102,7 +100,10 @@ public class WatchExtensionSupport {
void createBundle(NestedSetBuilder<Artifact> filesToBuild,
ObjcProvider.Builder objcProviderBuilder, XcodeProvider.Builder xcodeProviderBuilder)
throws InterruptedException {
- WatchUtils.addXcodeSettings(ruleContext, xcodeProviderBuilder);
+
+ if (WatchUtils.isBuildingForWatchOS1Version(watchOSVersion)) {
+ WatchUtils.addXcodeSettings(ruleContext, xcodeProviderBuilder);
+ }
registerWatchExtensionAutomaticPlistAction();
@@ -142,26 +143,35 @@ public class WatchExtensionSupport {
ObjcRuleClasses.objcConfiguration(ruleContext).getMinimumOs()),
releaseBundling.build());
+ releaseBundlingSupport.registerActions(DsymOutputType.APP);
+
+ if (WatchUtils.isBuildingForWatchOS1Version(watchOSVersion)) {
+ releaseBundlingSupport.addXcodeSettings(xcodeProviderBuilder);
+ }
+
releaseBundlingSupport
- .registerActions(DsymOutputType.APP)
- .addXcodeSettings(xcodeProviderBuilder)
.addFilesToBuild(filesToBuild, DsymOutputType.APP)
.validateResources()
.validateAttributes();
- XcodeSupport xcodeSupport = new XcodeSupport(ruleContext)
- .addFilesToBuild(filesToBuild)
- .addXcodeSettings(xcodeProviderBuilder, objcProvider,
- watchOSVersion.getExtensionXcodeProductType(),
- ruleContext.getFragment(AppleConfiguration.class).getDependencySingleArchitecture(),
- configurationDistinguisher)
- .addDummySource(xcodeProviderBuilder);
-
- for (Attribute attribute : dependencyAttributes) {
- xcodeSupport.addDependencies(xcodeProviderBuilder, attribute);
- }
-
if (WatchUtils.isBuildingForWatchOS1Version(watchOSVersion)) {
+ XcodeSupport xcodeSupport =
+ new XcodeSupport(ruleContext)
+ .addFilesToBuild(filesToBuild)
+ .addXcodeSettings(
+ xcodeProviderBuilder,
+ objcProvider,
+ watchOSVersion.getExtensionXcodeProductType(),
+ ruleContext
+ .getFragment(AppleConfiguration.class)
+ .getDependencySingleArchitecture(),
+ configurationDistinguisher)
+ .addDummySource(xcodeProviderBuilder);
+
+ for (Attribute attribute : dependencyAttributes) {
+ xcodeSupport.addDependencies(xcodeProviderBuilder, attribute);
+ }
+
// Generate xcodeproj for watch OS 1 extension as the main target with watch application
// target as the dependency.
xcodeProviderBuilder.addPropagatedDependencies(
@@ -297,5 +307,4 @@ public class WatchExtensionSupport {
return ruleContext.getPrerequisiteArtifact(attribute, Mode.TARGET);
}
}
-
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/WatchUtils.java b/src/main/java/com/google/devtools/build/lib/rules/objc/WatchUtils.java
index 4909c2553c..70093373ad 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/WatchUtils.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/WatchUtils.java
@@ -28,27 +28,45 @@ import com.google.devtools.build.lib.rules.apple.Platform.PlatformType;
import com.google.devtools.build.xcode.xcodegen.proto.XcodeGenProtos.XcodeprojBuildSetting;
/**
- * Contains support methods for common processing and generating of watch extension and
- * application bundles.
+ * Contains support methods for common processing and generating of watch extension and application
+ * bundles.
*/
+// TODO(b/30503590): Refactor this into a support class -- such classes are better than this static
+// utility.
final class WatchUtils {
+ @VisibleForTesting
+ /** Bundle directory format for watch applications for watch OS 2. */
+ static final String WATCH2_APP_BUNDLE_DIR_FORMAT = "Watch/%s.app";
+
/**
* Supported Apple watch OS versions.
*/
enum WatchOSVersion {
- OS1(XcodeProductType.WATCH_OS1_APPLICATION, XcodeProductType.WATCH_OS1_EXTENSION,
- "WatchKitSupport");
+ OS1(
+ XcodeProductType.WATCH_OS1_APPLICATION,
+ XcodeProductType.WATCH_OS1_EXTENSION,
+ ReleaseBundlingSupport.APP_BUNDLE_DIR_FORMAT,
+ "WatchKitSupport"),
+ OS2(
+ XcodeProductType.WATCH_OS2_APPLICATION,
+ XcodeProductType.WATCH_OS2_EXTENSION,
+ WATCH2_APP_BUNDLE_DIR_FORMAT,
+ "WatchKitSupport2");
private final XcodeProductType applicationXcodeProductType;
private final XcodeProductType extensionXcodeProductType;
+ private final String applicationBundleDirFormat;
private final String watchKitSupportDirName;
- WatchOSVersion(XcodeProductType applicationXcodeProductType,
+ WatchOSVersion(
+ XcodeProductType applicationXcodeProductType,
XcodeProductType extensionXcodeProductType,
+ String applicationBundleDirFormat,
String watchKitSupportDirName) {
this.applicationXcodeProductType = applicationXcodeProductType;
this.extensionXcodeProductType = extensionXcodeProductType;
+ this.applicationBundleDirFormat = applicationBundleDirFormat;
this.watchKitSupportDirName = watchKitSupportDirName;
}
@@ -66,6 +84,11 @@ final class WatchUtils {
return extensionXcodeProductType;
}
+ /** Returns the bundle directory format of the watch application relative to its container. */
+ String getApplicationBundleDirFormat() {
+ return applicationBundleDirFormat;
+ }
+
/**
* Returns the name of the directory in the final iOS bundle which should contain the WatchKit
* support stub.
@@ -140,12 +163,16 @@ final class WatchUtils {
watchSupportZip.getFilename(),
watchKitSupportDirName));
- ruleContext.registerAction(ObjcRuleClasses.spawnAppleEnvActionBuilder(ruleContext,
- ruleContext.getFragment(AppleConfiguration.class).getMultiArchPlatform(PlatformType.IOS))
- .setProgressMessage("Copying Watchkit support to app bundle")
- .setShellCommand(ImmutableList.of("/bin/bash", "-c", Joiner.on(" ").join(command)))
- .addOutput(watchSupportZip)
- .build(ruleContext));
+ ruleContext.registerAction(
+ ObjcRuleClasses.spawnAppleEnvActionBuilder(
+ ruleContext,
+ ruleContext
+ .getFragment(AppleConfiguration.class)
+ .getMultiArchPlatform(PlatformType.WATCHOS))
+ .setProgressMessage("Copying Watchkit support to app bundle")
+ .setShellCommand(ImmutableList.of("/bin/bash", "-c", Joiner.on(" ").join(command)))
+ .addOutput(watchSupportZip)
+ .build(ruleContext));
objcProviderBuilder.add(ROOT_MERGE_ZIP, watchSupportZip(ruleContext));
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/XcodeProductType.java b/src/main/java/com/google/devtools/build/lib/rules/objc/XcodeProductType.java
index df912c3df3..bc4bb96722 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/XcodeProductType.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/XcodeProductType.java
@@ -26,7 +26,9 @@ enum XcodeProductType {
EXTENSION("com.apple.product-type.app-extension"),
FRAMEWORK("com.apple.product-type.framework"),
WATCH_OS1_APPLICATION("com.apple.product-type.application.watchapp"),
- WATCH_OS1_EXTENSION("com.apple.product-type.watchkit-extension");
+ WATCH_OS2_APPLICATION("com.apple.product-type.application.watchapp2"),
+ WATCH_OS1_EXTENSION("com.apple.product-type.watchkit-extension"),
+ WATCH_OS2_EXTENSION("com.apple.product-type.watchkit2-extension");
private final String identifier;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/XcodeProvider.java b/src/main/java/com/google/devtools/build/lib/rules/objc/XcodeProvider.java
index 38e39348a6..36cd017fd1 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/XcodeProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/XcodeProvider.java
@@ -53,7 +53,6 @@ import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.devtools.build.xcode.xcodegen.proto.XcodeGenProtos.DependencyControl;
import com.google.devtools.build.xcode.xcodegen.proto.XcodeGenProtos.TargetControl;
import com.google.devtools.build.xcode.xcodegen.proto.XcodeGenProtos.XcodeprojBuildSetting;
-
import java.util.Arrays;
import java.util.EnumSet;
import java.util.HashMap;
@@ -508,10 +507,15 @@ public final class XcodeProvider implements TransitiveInfoProvider {
}
@VisibleForTesting
- static final EnumSet<XcodeProductType> CAN_LINK_PRODUCT_TYPES = EnumSet.of(
- XcodeProductType.APPLICATION, XcodeProductType.BUNDLE, XcodeProductType.UNIT_TEST,
- XcodeProductType.EXTENSION, XcodeProductType.FRAMEWORK, XcodeProductType.WATCH_OS1_EXTENSION,
- XcodeProductType.WATCH_OS1_APPLICATION);
+ static final EnumSet<XcodeProductType> CAN_LINK_PRODUCT_TYPES =
+ EnumSet.of(
+ XcodeProductType.APPLICATION,
+ XcodeProductType.BUNDLE,
+ XcodeProductType.UNIT_TEST,
+ XcodeProductType.EXTENSION,
+ XcodeProductType.FRAMEWORK,
+ XcodeProductType.WATCH_OS1_EXTENSION,
+ XcodeProductType.WATCH_OS1_APPLICATION);
/**
* Returns the name of the Xcode target that corresponds to a build target with the given name.
@@ -637,8 +641,9 @@ public final class XcodeProvider implements TransitiveInfoProvider {
// but do have a dummy source file to make Xcode happy.
boolean hasSources = dependency.compilationArtifacts.isPresent()
&& dependency.compilationArtifacts.get().getArchive().isPresent();
- if (hasSources || (dependency.productType == XcodeProductType.BUNDLE
- || (dependency.productType == XcodeProductType.WATCH_OS1_APPLICATION))) {
+ if (hasSources
+ || (dependency.productType == XcodeProductType.BUNDLE
+ || (dependency.productType == XcodeProductType.WATCH_OS1_APPLICATION))) {
String dependencyXcodeTargetName = dependency.dependencyXcodeTargetName();
Set<DependencyControl> set = jreTargetNames.contains(dependencyXcodeTargetName)
? jreDependencySet : dependencySet;