// Copyright 2014 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.MERGE_ZIP;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Ordering;
import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.analysis.config.BuildOptions;
import com.google.devtools.build.lib.packages.Attribute.SplitTransition;
import com.google.devtools.build.lib.rules.apple.AppleCommandLineOptions;
import com.google.devtools.build.lib.rules.apple.AppleConfiguration;
import com.google.devtools.build.lib.rules.apple.AppleConfiguration.ConfigurationDistinguisher;
import com.google.devtools.build.lib.rules.apple.ApplePlatform.PlatformType;
import com.google.devtools.build.lib.rules.apple.DottedVersion;
import com.google.devtools.build.lib.rules.objc.ReleaseBundlingSupport.SplitArchTransition;
import java.io.Serializable;
import javax.annotation.Nullable;
/**
* Implementation for {@code ios_extension}.
*
* @deprecated The native bundling rules have been deprecated. This class will be removed in the
* future.
*/
@Deprecated
public class IosExtension extends ReleaseBundlingTargetFactory {
// Apple only accepts extensions starting at 8.0.
@VisibleForTesting
static final DottedVersion EXTENSION_MINIMUM_OS_VERSION = DottedVersion.fromString("8.0");
/**
* Transition that when applied to a target generates a configured target for each value in
* {@code --ios_multi_cpus}, such that {@code --ios_cpu} is set to a different one of those values
* in the configured targets.
*
*
Also ensures that, no matter whether {@code --ios_multi_cpus} is set, {@code
* --ios_minimum_os} is at least {@code 8.0} as Apple requires this for extensions.
*/
static final SplitTransition MINIMUM_OS_AND_SPLIT_ARCH_TRANSITION =
new ExtensionSplitArchTransition(EXTENSION_MINIMUM_OS_VERSION,
ConfigurationDistinguisher.IOS_EXTENSION);
public IosExtension() {
super(
ReleaseBundlingSupport.EXTENSION_BUNDLE_DIR_FORMAT,
ImmutableSet.of(new Attribute("binary", Mode.SPLIT)));
}
@Override
protected DottedVersion bundleMinimumOsVersion(RuleContext ruleContext) {
return determineMinimumOsVersion(
ruleContext.getFragment(AppleConfiguration.class)
.getMinimumOsForPlatformType(PlatformType.IOS),
EXTENSION_MINIMUM_OS_VERSION);
}
@Override
protected ObjcProvider exposedObjcProvider(
RuleContext ruleContext, ReleaseBundlingSupport releaseBundlingSupport)
throws InterruptedException {
ObjcProvider.Builder builder =
new ObjcProvider.Builder()
// Nest this target's bundle under final IPA
.add(MERGE_ZIP, ruleContext.getImplicitOutputArtifact(ReleaseBundlingSupport.IPA));
releaseBundlingSupport.addExportedDebugArtifacts(builder, DsymOutputType.APP);
return builder.build();
}
/**
* Overrides (if necessary) any flag-set minimum iOS version for extensions only with given
* minimum OS version.
*
* Extensions are not accepted by Apple below given mininumOSVersion. While applications built
* with a minimum iOS version of less than give version may contain extensions in their bundle,
* the extension itself needs to be built with given version or higher.
*
* @param fromFlag the minimum OS version from command line flag
* @param minimumOSVersion the minumum OS version the extension should be built with
*/
private static DottedVersion determineMinimumOsVersion(@Nullable DottedVersion fromFlag,
DottedVersion minimumOSVersion) {
if (fromFlag == null) {
return minimumOSVersion;
}
return Ordering.natural().max(fromFlag, minimumOSVersion);
}
/**
* Split transition that configures the minimum iOS version in addition to architecture splitting.
*/
static class ExtensionSplitArchTransition extends SplitArchTransition
implements Serializable {
private final DottedVersion minimumOSVersion;
private final ConfigurationDistinguisher configurationDistinguisher;
ExtensionSplitArchTransition(DottedVersion minimumOSVersion,
ConfigurationDistinguisher configurationDistinguisher) {
this.minimumOSVersion = minimumOSVersion;
this.configurationDistinguisher = configurationDistinguisher;
}
@Override
protected ImmutableList defaultOptions(BuildOptions originalOptions) {
AppleCommandLineOptions appleOptions = originalOptions.get(AppleCommandLineOptions.class);
DottedVersion newMinimumVersion = determineMinimumOsVersion(appleOptions.iosMinimumOs,
minimumOSVersion);
if (newMinimumVersion.equals(appleOptions.iosMinimumOs)) {
return ImmutableList.of();
}
BuildOptions splitOptions = originalOptions.clone();
setMinimumOsVersion(splitOptions, newMinimumVersion);
splitOptions.get(AppleCommandLineOptions.class).configurationDistinguisher =
getConfigurationDistinguisher();
return ImmutableList.of(splitOptions);
}
@Override
protected void setAdditionalOptions(BuildOptions splitOptions, BuildOptions originalOptions) {
DottedVersion fromFlag = originalOptions.get(AppleCommandLineOptions.class).iosMinimumOs;
setMinimumOsVersion(splitOptions, determineMinimumOsVersion(fromFlag, minimumOSVersion));
}
@Override
protected ConfigurationDistinguisher getConfigurationDistinguisher() {
return configurationDistinguisher;
}
private void setMinimumOsVersion(BuildOptions splitOptions, DottedVersion newMinimumVersion) {
splitOptions.get(AppleCommandLineOptions.class).iosMinimumOs = newMinimumVersion;
}
}
}