Commit 3cf03bbd authored by Samuel Giddins's avatar Samuel Giddins Committed by GitHub

Merge pull request #5502 from benasher44/basher_improved_extension_handling

Improve handling of app and watch os 1 extensions
parents 70487ea7 fe6f6521
......@@ -34,10 +34,18 @@ To install release candidates run `[sudo] gem install cocoapods --pre`
##### Bug Fixes
* Improve handling of app extensions, watch os 1 extensions
and framework targets
[benasher44](https://github.com/benasher44)
[#4203](https://github.com/CocoaPods/CocoaPods/issues/4203)
* Fix local pod platform conflict error message.
[Muhammed Yavuz Nuzumlalı](https://github.com/manuyavuz)
[#5052](https://github.com/CocoaPods/CocoaPods/issues/5052)
##### Bug Fixes
* Fix installing pods with `use_frameworks` when deduplication is disabled.
[Samuel Giddins](https://github.com/segiddins)
[#5481](https://github.com/CocoaPods/CocoaPods/issues/5481)
......
......@@ -24,7 +24,7 @@ GIT
GIT
remote: https://github.com/CocoaPods/Xcodeproj.git
revision: 1b15f4c79303843e8f370afa9dd74b8ad0329785
revision: 796dec1d5abcdfc02ca1b5b8748d91c3f3e943b0
branch: master
specs:
xcodeproj (1.1.0)
......@@ -86,7 +86,7 @@ GIT
GIT
remote: https://github.com/segiddins/json.git
revision: d4011cabfaa80e9b0da81947b5e9b38dd47359db
revision: a9588bc4334c2f5bf985f255b61c05eafdcd8907
branch: seg-1.7.7-ruby-2.2
specs:
json (1.7.7)
......
......@@ -4,7 +4,7 @@ module Pod
# Generates the xcconfigs for the aggregate targets.
#
class AggregateXCConfig
# @return [Target] the target represented by this xcconfig.
# @return [AggregateTarget] the target represented by this xcconfig.
#
attr_reader :target
......@@ -61,7 +61,14 @@ module Pod
'FRAMEWORK_SEARCH_PATHS' => '$(inherited) ',
'LIBRARY_SEARCH_PATHS' => '$(inherited) ',
}
if pod_targets.any?(&:uses_swift?)
# For embedded targets, which live in a host target, CocoaPods
# copies all of the embedded target's pod_targets its host
# target. Therefore, this check will properly require the Swift
# libs in the host target, if the embedded target has any pod targets
# that use Swift. Setting this for the embedded target would
# cause an App Store rejection because frameworks cannot be embedded
# in embedded targets.
if !target.requires_host_target? && pod_targets.any?(&:uses_swift?)
config['EMBEDDED_CONTENT_CONTAINS_SWIFT'] = 'YES'
end
@xcconfig = Xcodeproj::Config.new(config)
......
......@@ -226,6 +226,61 @@ module Pod
private
# Copies the pod_targets of any of the app embedded aggregate targets into
# their potential host aggregate target, if that potential host aggregate target's
# user_target hosts any of the app embedded aggregate targets' user_targets
#
# @param [AggregateTarget] aggregate_target the aggregate target whose user_target
# might host one or more of the embedded aggregate targets' user_targets
#
# @param [Array<AggregateTarget>] embedded_aggregate_targets the aggregate targets
# representing the embedded targets to be integrated
#
def copy_embedded_target_pod_targets_to_host(aggregate_target, embedded_aggregate_targets)
return if aggregate_target.requires_host_target?
# Get the uuids of the aggregate_target's user_targets' embedded targets if any
embedded_uuids = Set.new(aggregate_target.user_targets.map do |target|
aggregate_target.user_project.embedded_targets_in_native_target(target).map(&:uuid)
end.flatten)
return if embedded_uuids.empty?
embedded_aggregate_targets.each do |embedded_target|
next unless embedded_target.user_targets.map(&:uuid).any? do |embedded_uuid|
embedded_uuids.include? embedded_uuid
end
raise Informative, "#{aggregate_target.name} must call use_frameworks! because it is hosting an embedded target that calls use_frameworks!." unless aggregate_target.requires_frameworks?
pod_target_names = aggregate_target.pod_targets.map(&:name)
# This embedded target is hosted by the aggregate target's user_target; copy over the non-duplicate pod_targets
aggregate_target.pod_targets = aggregate_target.pod_targets + embedded_target.pod_targets.select do |pod_target|
!pod_target_names.include? pod_target.name
end
end
end
# Raises an error if there are embedded targets in the Podfile, but
# their host targets have not been declared in the Podfile
#
# @param [Array<AggregateTarget>] aggregate_targets the generated
# aggregate targets
#
# @param [Array<AggregateTarget>] embedded_aggregate_targets the aggregate targets
# representing the embedded targets to be integrated
#
def verify_host_targets_in_podfile(aggregate_targets, embedded_aggregate_targets)
aggregate_target_uuids = Set.new aggregate_targets.map(&:user_targets).flatten.map(&:uuid)
embedded_targets_missing_hosts = []
embedded_aggregate_targets.each do |target|
host_uuids = target.user_targets.map do |user_target|
target.user_project.host_targets_for_embedded_target(user_target).map(&:uuid)
end.flatten
embedded_targets_missing_hosts << target unless host_uuids.any? do |uuid|
aggregate_target_uuids.include? uuid
end
end
unless embedded_targets_missing_hosts.empty?
raise Informative, "Unable to find host target for #{embedded_targets_missing_hosts.map(&:name).join(', ')}. Please add the host targets for the embedded targets to the Podfile."
end
end
# Creates the models that represent the targets generated by CocoaPods.
#
# @return [Array<AggregateTarget>]
......@@ -236,6 +291,14 @@ module Pod
aggregate_targets = specs_by_target.keys.map do |target_definition|
generate_target(target_definition, pod_targets)
end
if installation_options.integrate_targets?
# Copy embedded target pods that cannot have their pods embedded as frameworks to their host targets
embedded_targets = aggregate_targets.select(&:requires_host_target?).select(&:requires_frameworks?)
verify_host_targets_in_podfile(aggregate_targets, embedded_targets)
aggregate_targets.each do |target|
copy_embedded_target_pod_targets_to_host(target, embedded_targets)
end
end
aggregate_targets.each do |target|
target.search_paths_aggregate_targets = aggregate_targets.select do |aggregate_target|
target.target_definition.targets_to_inherit_search_paths.include?(aggregate_target.target_definition)
......@@ -277,6 +340,7 @@ module Pod
target.pod_targets = pod_targets.select do |pod_target|
pod_target.target_definitions.include?(target_definition)
end
target
end
......
......@@ -20,7 +20,10 @@ module Pod
# @return [Array<Symbol>] the symbol types, which require that the pod
# frameworks are embedded in the output directory / product bundle.
#
EMBED_FRAMEWORK_TARGET_TYPES = [:application, :unit_test_bundle, :ui_test_bundle, :app_extension, :watch_extension, :watch2_extension].freeze
# @note This does not include :app_extension or :watch_extension because
# these types must have their frameworks embedded in their host targets
#
EMBED_FRAMEWORK_TARGET_TYPES = [:application, :unit_test_bundle, :ui_test_bundle, :watch2_extension].freeze
# @return [String] the name of the embed frameworks phase
#
......@@ -54,6 +57,7 @@ module Pod
add_pods_library
add_embed_frameworks_script_phase
remove_embed_frameworks_script_phase_from_embedded_targets
add_copy_resources_script_phase
add_check_manifest_lock_script_phase
end
......@@ -110,6 +114,20 @@ module Pod
end
end
# Removes the embed frameworks build phase from embedded targets
#
# @note Older versions of CocoaPods would add this build phase to embedded
# targets. They should be removed on upgrade because embedded targets
# will have their frameworks embedded in their host targets.
#
def remove_embed_frameworks_script_phase_from_embedded_targets
native_targets.each do |native_target|
if AggregateTarget::EMBED_FRAMEWORKS_IN_HOST_TARGET_TYPES.include? native_target.symbol_type
remove_embed_frameworks_script_phase(native_target)
end
end
end
def add_embed_frameworks_script_phase_to_target(native_target)
phase = create_or_update_build_phase(native_target, EMBED_FRAMEWORK_PHASE_NAME)
script_path = target.embed_frameworks_script_relative_path
......@@ -121,7 +139,7 @@ module Pod
# @param [PBXNativeTarget] native_target
#
def remove_embed_frameworks_script_phase(native_target)
embed_build_phase = native_target.shell_script_build_phases.find { |bp| bp.name == EMBED_FRAMEWORK_PHASE_NAME }
embed_build_phase = native_target.shell_script_build_phases.find { |bp| bp.name && bp.name.end_with?(EMBED_FRAMEWORK_PHASE_NAME) }
return unless embed_build_phase.present?
native_target.build_phases.delete(embed_build_phase)
end
......
......@@ -21,7 +21,13 @@ module Pod
create_module_map
create_umbrella_header
end
create_embed_frameworks_script
# Because embedded targets live in their host target, CocoaPods
# copies all of the embedded target's pod_targets to its host
# targets. Having this script for the embedded target would
# cause an App Store rejection because frameworks cannot be
# embedded in embedded targets.
#
create_embed_frameworks_script unless target.requires_host_target?
create_bridge_support_file
create_copy_resources_script
create_acknowledgements
......
......@@ -7,6 +7,9 @@ module Pod
# generated this target.
attr_reader :target_definition
# Product types where the product's frameworks must be embedded in a host target
EMBED_FRAMEWORKS_IN_HOST_TARGET_TYPES = [:app_extension, :framework, :messages_extension, :watch_extension].freeze
# Initialize a new instance
#
# @param [TargetDefinition] target_definition @see target_definition
......@@ -23,6 +26,22 @@ module Pod
@xcconfigs = {}
end
# @return [Boolean] True if the user_target's pods are
# for an extension and must be embedded in a host,
# target, otherwise false.
#
def requires_host_target?
# If we don't have a user_project, then we can't
# glean any info about how this target is going to
# be integrated, so return false since we can't know
# for sure that this target refers to an extension
# target that would require a host target
return false if user_project.nil?
symbol_types = user_targets.map(&:symbol_type).uniq
raise ArgumentError, "Expected single kind of user_target for #{name}. Found #{symbol_types.join(', ')}." unless symbol_types.count == 1
EMBED_FRAMEWORKS_IN_HOST_TARGET_TYPES.include? symbol_types[0]
end
# @return [String] the label for the target.
#
def label
......
//
// AppDelegate.swift
// Sample Extensions Project
//
// Created by Benjamin Asher on 6/10/16.
// Copyright © 2016 CocoaPods. All rights reserved.
//
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
return true
}
func applicationWillResignActive(application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
func applicationDidEnterBackground(application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(application: UIApplication) {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}
{
"images" : [
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="8150" systemVersion="15A204g" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" initialViewController="01J-lp-oVM">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8122"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/>
<viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<animations/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
</document>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6211" systemVersion="14A298i" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6204"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
//
// ViewController.swift
// Sample Extensions Project
//
// Created by Benjamin Asher on 6/10/16.
// Copyright © 2016 CocoaPods. All rights reserved.
//
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6211" systemVersion="14A298i" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" initialViewController="M4Y-Lb-cyx">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6204"/>
</dependencies>
<scenes>
<!--Today View Controller-->
<scene sceneID="cwh-vc-ff4">
<objects>
<viewController id="M4Y-Lb-cyx" customClass="TodayViewController" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Ft6-oW-KC0"/>
<viewControllerLayoutGuide type="bottom" id="FKl-LY-JtV"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" simulatedAppContext="notificationCenter" id="S3S-Oj-5AN">
<rect key="frame" x="0.0" y="0.0" width="320" height="37"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="top" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Hello World" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" preferredMaxLayoutWidth="280" translatesAutoresizingMaskIntoConstraints="NO" id="GcN-lo-r42">
<rect key="frame" x="20" y="8" width="280" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" cocoaTouchSystemColor="lightTextColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstItem="FKl-LY-JtV" firstAttribute="top" secondItem="GcN-lo-r42" secondAttribute="bottom" constant="20" symbolic="YES" id="0Q0-KW-PJ6"/>
<constraint firstItem="GcN-lo-r42" firstAttribute="leading" secondItem="S3S-Oj-5AN" secondAttribute="leading" constant="20" symbolic="YES" id="6Vq-gs-PHe"/>
<constraint firstAttribute="trailing" secondItem="GcN-lo-r42" secondAttribute="trailing" constant="20" symbolic="YES" id="L8K-9R-egU"/>
<constraint firstItem="GcN-lo-r42" firstAttribute="top" secondItem="Ft6-oW-KC0" secondAttribute="bottom" constant="20" symbolic="YES" id="mYS-Cv-VNx"/>
</constraints>
</view>
<extendedEdge key="edgesForExtendedLayout"/>
<nil key="simulatedStatusBarMetrics"/>
<nil key="simulatedTopBarMetrics"/>
<nil key="simulatedBottomBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<size key="freeformSize" width="320" height="37"/>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="vXp-U4-Rya" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="516" y="285"/>
</scene>
</scenes>
<simulatedMetricsContainer key="defaultSimulatedMetrics">
<simulatedStatusBarMetrics key="statusBar"/>
<simulatedOrientationMetrics key="orientation"/>
<simulatedScreenMetrics key="destination" type="retina4"/>
</simulatedMetricsContainer>
</document>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>Today Extension</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionMainStoryboard</key>
<string>MainInterface</string>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.widget-extension</string>
</dict>
</dict>
</plist>
//
// TodayViewController.swift
// Today Extension
//
// Created by Benjamin Asher on 6/10/16.
// Copyright © 2016 CocoaPods. All rights reserved.
//
import UIKit
import NotificationCenter
class TodayViewController: UIViewController, NCWidgetProviding {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view from its nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func widgetPerformUpdateWithCompletionHandler(completionHandler: ((NCUpdateResult) -> Void)) {
// Perform any setup necessary in order to update the view.
// If an error is encountered, use NCUpdateResult.Failed
// If there's no update required, use NCUpdateResult.NoData
// If there's an update, use NCUpdateResult.NewData
completionHandler(NCUpdateResult.NewData)
}
}
......@@ -250,6 +250,12 @@ module Pod
@generator.send(:pod_targets).each { |pt| pt.stubs(:uses_swift?).returns(false) }
@generator.generate.to_hash['EMBEDDED_CONTENT_CONTAINS_SWIFT'].should.be.nil
end
it 'does not set EMBEDDED_CONTENT_CONTAINS_SWIFT when there is swift, but the target is an extension' do
@target.stubs(:requires_host_target?).returns(true)
@generator.send(:pod_targets).first.stubs(:uses_swift?).returns(true)
@generator.generate.to_hash['EMBEDDED_CONTENT_CONTAINS_SWIFT'].should.be.nil
end
end
#-----------------------------------------------------------------------#
......
......@@ -671,6 +671,87 @@ module Pod
#-------------------------------------------------------------------------#
describe 'extension targets' do
before do
SpecHelper.create_sample_app_copy_from_fixture('Sample Extensions Project')
@podfile = Pod::Podfile.new do
source SpecHelper.test_repo_url
platform :ios, '6.0'
project 'Sample Extensions Project/Sample Extensions Project'
target 'Sample Extensions Project' do
pod 'JSONKit', '1.4'
end
target 'Today Extension' do
pod 'monkey'
end
end
end
it 'copies extension pod targets to host target, when use_frameworks!' do
@podfile.use_frameworks!
analyzer = Pod::Installer::Analyzer.new(config.sandbox, @podfile)
result = analyzer.analyze
result.targets.flat_map { |at| at.pod_targets.map { |pt| "#{at.name}/#{pt.name}" } }.sort.should == [
'Pods-Sample Extensions Project/JSONKit',
'Pods-Sample Extensions Project/monkey',
'Pods-Today Extension/monkey',
].sort
end
it 'does not copy extension pod targets to host target, when not use_frameworks!' do
analyzer = Pod::Installer::Analyzer.new(config.sandbox, @podfile)
result = analyzer.analyze
result.targets.flat_map { |at| at.pod_targets.map { |pt| "#{at.name}/#{pt.name}" } }.sort.should == [
'Pods-Sample Extensions Project/JSONKit',
'Pods-Today Extension/monkey',
].sort
end
it "raises when unable to find an extension's host target" do
podfile = Pod::Podfile.new do
source SpecHelper.test_repo_url
use_frameworks!
platform :ios, '6.0'
project 'Sample Extensions Project/Sample Extensions Project'
target 'Today Extension' do
pod 'monkey'
end
end
analyzer = Pod::Installer::Analyzer.new(config.sandbox, podfile)
should.raise Informative do
analyzer.analyze
end.message.should.match /Unable to find host target for Pods-Today Extension. Please add the host targets for the embedded targets to the Podfile/
end
it 'raises when the extension calls use_frameworks!, but the host target does not' do
podfile = Pod::Podfile.new do
source SpecHelper.test_repo_url
platform :ios, '6.0'
project 'Sample Extensions Project/Sample Extensions Project'
target 'Sample Extensions Project' do
pod 'JSONKit', '1.4'
end
target 'Today Extension' do
use_frameworks!
pod 'monkey'
end
end
analyzer = Pod::Installer::Analyzer.new(config.sandbox, podfile)
should.raise Informative do
analyzer.analyze
end.message.should.match /Pods-Sample Extensions Project must call use_frameworks! because it is hosting an embedded target that calls use_frameworks!/
end
end
#-------------------------------------------------------------------------#
describe 'Private helpers' do
describe '#sources' do
describe 'when there are no explicit sources' do
......
......@@ -147,22 +147,22 @@ module Pod
phase.nil?.should == true
end
it 'adds an embed frameworks build phase if the target to integrate is an app extension' do
it 'does not add an embed frameworks build phase if the target to integrate is an app extension' do
@pod_bundle.stubs(:requires_frameworks? => true)
target = @target_integrator.send(:native_targets).first
target.stubs(:symbol_type).returns(:app_extension)
@target_integrator.integrate!
phase = target.shell_script_build_phases.find { |bp| bp.name == @embed_framework_phase_name }
phase.nil?.should == false
phase.nil?.should == true
end
it 'adds an embed frameworks build phase if the target to integrate is a watch extension' do
it 'does not add an embed frameworks build phase if the target to integrate is a watch extension' do
@pod_bundle.stubs(:requires_frameworks? => true)
target = @target_integrator.send(:native_targets).first
target.stubs(:symbol_type).returns(:watch_extension)
@target_integrator.integrate!
phase = target.shell_script_build_phases.find { |bp| bp.name == @embed_framework_phase_name }
phase.nil?.should == false
phase.nil?.should == true
end
it 'adds an embed frameworks build phase if the target to integrate is a watchOS 2 extension' do
......@@ -202,6 +202,42 @@ module Pod
phase = target.shell_script_build_phases.find { |bp| bp.name == @embed_framework_phase_name }
phase.nil?.should == false
end
it 'removes embed frameworks build phases from app extension targets' do
@pod_bundle.stubs(:requires_frameworks? => true)
@target_integrator.integrate!
target = @target_integrator.send(:native_targets).first
phase = target.shell_script_build_phases.find { |bp| bp.name == @embed_framework_phase_name }
phase.nil?.should == false
target.stubs(:symbol_type).returns(:app_extension)
@target_integrator.integrate!
phase = target.shell_script_build_phases.find { |bp| bp.name == @embed_framework_phase_name }
phase.nil?.should == true
end
it 'removes embed frameworks build phases from watch extension targets' do
@pod_bundle.stubs(:requires_frameworks? => true)
@target_integrator.integrate!
target = @target_integrator.send(:native_targets).first
phase = target.shell_script_build_phases.find { |bp| bp.name == @embed_framework_phase_name }
phase.nil?.should == false
target.stubs(:symbol_type).returns(:watch_extension)
@target_integrator.integrate!
phase = target.shell_script_build_phases.find { |bp| bp.name == @embed_framework_phase_name }
phase.nil?.should == true
end
it 'removes embed frameworks build phases from framework targets' do
@pod_bundle.stubs(:requires_frameworks? => true)
@target_integrator.integrate!
target = @target_integrator.send(:native_targets).first
phase = target.shell_script_build_phases.find { |bp| bp.name == @embed_framework_phase_name }
phase.nil?.should == false
target.stubs(:symbol_type).returns(:framework)
@target_integrator.integrate!
phase = target.shell_script_build_phases.find { |bp| bp.name == @embed_framework_phase_name }
phase.nil?.should == true
end
end
describe 'Private helpers' do
......
......@@ -226,6 +226,25 @@ module Pod
dummy = support_files_dir + 'Pods-SampleProject-dummy.m'
dummy.read.should.include?('@interface PodsDummy_Pods')
end
it 'creates an embed frameworks script, if the target does not require a host target' do
@pod_target.stubs(:requires_frameworks? => true)
@target.stubs(:requires_frameworks? => true)
@installer.install!
support_files_dir = config.sandbox.target_support_files_dir('Pods-SampleProject')
script = support_files_dir + 'Pods-SampleProject-frameworks.sh'
File.exist?(script).should == true
end
it 'does not create an embed frameworks script, if the target requires a host target' do
@pod_target.stubs(:requires_frameworks? => true)
@target.stubs(:requires_frameworks? => true)
@target.stubs(:requires_host_target? => true)
@installer.install!
support_files_dir = config.sandbox.target_support_files_dir('Pods-SampleProject')
script = support_files_dir + 'Pods-SampleProject-frameworks.sh'
File.exist?(script).should == false
end
end
end
end
......
......@@ -193,6 +193,62 @@ module Pod
@target.requires_frameworks?.should == false
end
end
describe 'Target might require a host target' do
before do
target_definition = Podfile::TargetDefinition.new('Pods', nil)
target_definition.abstract = false
@target = AggregateTarget.new(target_definition, config.sandbox)
project_path = SpecHelper.fixture('SampleProject/SampleProject.xcodeproj')
@target.user_project = Xcodeproj::Project.open(project_path)
@target.user_target_uuids = ['A346496C14F9BE9A0080D870']
end
it 'requires a host target for app extension targets' do
@target.user_targets.first.stubs(:symbol_type).returns(:app_extension)
@target.requires_host_target?.should == true
end
it 'requires a host target for watch extension targets' do
@target.user_targets.first.stubs(:symbol_type).returns(:watch_extension)
@target.requires_host_target?.should == true
end
it 'requires a host target for framework targets' do
@target.user_targets.first.stubs(:symbol_type).returns(:framework)
@target.requires_host_target?.should == true
end
it 'requires a host target for messages extension targets' do
@target.user_targets.first.stubs(:symbol_type).returns(:messages_extension)
@target.requires_host_target?.should == true
end
it 'does not require a host target for watch 2 extension targets' do
@target.user_targets.first.stubs(:symbol_type).returns(:watch2_extension)
@target.requires_host_target?.should == false
end
it 'does not require a host target for application targets' do
@target.user_targets.first.stubs(:symbol_type).returns(:application)
@target.requires_host_target?.should == false
end
it 'does not require a host target, if there is no user project (manual integration)' do
@target.user_project = nil
@target.user_target_uuids = []
@target.requires_host_target?.should == false
end
it 'raises an exception if more than one kind of user_target is found' do
@target.user_target_uuids << '51075D491521D0C100E39B41'
@target.user_targets.first.stubs(:symbol_type).returns(:app_extension)
@target.user_targets.last.stubs(:symbol_type).returns(:watch_extension)
should.raise ArgumentError do
@target.requires_host_target?
end.message.should.equal 'Expected single kind of user_target for Pods. Found app_extension, watch_extension.'
end
end
end
describe 'With frameworks' do
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment