Skip to content

Commit

Permalink
Configure dependencies per configuration.
Browse files Browse the repository at this point in the history
  • Loading branch information
segiddins authored and dnkoutso committed Oct 11, 2019
1 parent 1356017 commit 2db4a0a
Show file tree
Hide file tree
Showing 25 changed files with 612 additions and 270 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ To install release candidates run `[sudo] gem install cocoapods --pre`
[Dimitris Koutsogiorgas](https://github.com/dnkoutso)
[#9230](https://github.com/CocoaPods/CocoaPods/pull/9230)

* Configure dependencies per configuration.
[Samuel Giddins](https://github.com/segiddins)
[Dimitris Koutsogiorgas](https://github.com/dnkoutso)
[#9149](https://github.com/CocoaPods/CocoaPods/pull/9149)

* Include Podfile Plugin changes for incremental installation.
[Sebastian Shanus](https://github.com/sebastianv1)
[#9147](https://github.com/CocoaPods/CocoaPods/pull/9147)
Expand Down
21 changes: 21 additions & 0 deletions examples/multiple test specs Example/ByConfig/ByConfig.podspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
Pod::Spec.new do |s|
s.name = 'ByConfig'
s.version = '0.1.0'
s.summary = 'A short description of ByConfig.'
s.ios.deployment_target = '10.0'
s.author = { 'Jeff Overwatch' => '[email protected]' }
s.homepage = "https://github.com/"
s.license = 'MIT'
s.source = { :git => "https://github.com/<GITHUB_USERNAME>/ByConfig.git", :tag => s.version.to_s }

s.source_files = 'ByConfig/Classes/**/*'

s.swift_version = '4'

s.app_spec 'App' do |app_spec|
app_spec.source_files = 'ByConfig/App/**/*'

app_spec.dependency 'TestLib', configurations: %w[Debug]
app_spec.dependency 'HostedTestLib'
end
end
37 changes: 37 additions & 0 deletions examples/multiple test specs Example/ByConfig/ByConfig/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# OS X
.DS_Store

# Xcode
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata/
*.xccheckout
profile
*.moved-aside
DerivedData
*.hmap
*.ipa

# Bundler
.bundle

# Add this line if you want to avoid checking in source code from Carthage dependencies.
# Carthage/Checkouts

Carthage/Build

# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
#
# Note: if you ignore the Pods directory, make sure to uncomment
# `pod install` in .travis.yml
#
# Pods/
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import UIKit
import ByConfig
import HostedTestLib

#if DEBUG
import TestLib
#endif

class ViewController: UIViewController {
override func viewDidLoad() {
view.backgroundColor = .purple
}
}

@UIApplicationMain
class AppDelegate: NSObject, UIApplicationDelegate {
var window: UIWindow?

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
#if DEBUG
_ = TestLib()
#endif
_ = ByConfig()
_ = HostedTestLib()
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = UINavigationController(rootViewController: ViewController())
window?.makeKeyAndVisible()

return true
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import Foundation

public class ByConfig {
}
Original file line number Diff line number Diff line change
Expand Up @@ -183,11 +183,13 @@
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-InstallMultipleTestSpecs/Pods-InstallMultipleTestSpecs-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/ByConfig/ByConfig.framework",
"${BUILT_PRODUCTS_DIR}/HostedTestLib/HostedTestLib.framework",
"${BUILT_PRODUCTS_DIR}/TestLib/TestLib.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ByConfig.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/HostedTestLib.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/TestLib.framework",
);
Expand Down
1 change: 1 addition & 0 deletions examples/multiple test specs Example/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ target 'InstallMultipleTestSpecs' do
# Pods for InstallMultipleTestSpecs
pod 'TestLib', :path => 'TestLib', :testspecs => %w[UnitTests1 UnitTests2]
pod 'HostedTestLib', :path => 'HostedTestLib', :testspecs => %w[UnitTests3 UnitTests4]
pod 'ByConfig', path: 'ByConfig', appspecs: %w[App]
end
81 changes: 47 additions & 34 deletions lib/cocoapods/installer/analyzer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -415,11 +415,11 @@ def analyze_host_targets_in_podfile(aggregate_targets, embedded_aggregate_target

# Creates the models that represent the targets generated by CocoaPods.
#
# @param [Hash{Podfile::TargetDefinition => Array<ResolvedSpecification>}] resolver_specs_by_target
# @param [Hash{TargetDefinition => Array<ResolvedSpecification>}] resolver_specs_by_target
# mapping of targets to resolved specs (containing information about test usage)
# aggregate targets
#
# @param [Array<TargetInspection>] target_inspections
# @param [Hash{TargetDefinition => TargetInspectionResult}] target_inspections
# the user target inspections used to construct the aggregate and pod targets.
#
# @return [(Array<AggregateTarget>, Array<PodTarget>)] the list of aggregate targets generated,
Expand Down Expand Up @@ -481,7 +481,7 @@ def generate_targets(resolver_specs_by_target, target_inspections)
# @param [Hash{TargetDefinition => TargetInspectionResult}] target_inspections
# the user target inspections used to construct the aggregate and pod targets.
#
# @param [Hash{Podfile::TargetDefinition => Array<PodTarget>}] pod_targets_by_target_definition
# @param [Hash{TargetDefinition => Array<PodTarget>}] pod_targets_by_target_definition
# the pod targets grouped by target.
#
# @return [AggregateTarget]
Expand Down Expand Up @@ -541,16 +541,17 @@ def group_pod_targets_by_target_definition(pod_targets, resolver_specs_by_target
# @param [TargetDefinition] target_definition
# the target definition to use as the base for filtering
#
# @param [Hash{Podfile::TargetDefinition => Array<PodTarget>}] pod_targets_by_target_definition
# @param [Hash{TargetDefinition => Array<PodTarget>}] pod_targets_by_target_definition
# the pod targets grouped by target.
#
# @param [Array<String>] build_configurations
# The list of all build configurations the targets will be built for.
#
# @return [Hash<String => Array<PodTarget>>]
# @return [Hash{String => Array<PodTarget>}]
# the filtered list of pod targets, grouped by build configuration.
#
def filter_pod_targets_for_target_definition(target_definition, pod_targets_by_target_definition, build_configurations)
def filter_pod_targets_for_target_definition(target_definition, pod_targets_by_target_definition,
build_configurations)
pod_targets_by_build_config = Hash.new([].freeze)
build_configurations.each { |config| pod_targets_by_build_config[config] = [] }

Expand Down Expand Up @@ -587,7 +588,7 @@ def filter_pod_targets_for_target_definition(target_definition, pod_targets_by_t
# targets by grouping by platform and subspec by their root
# to create a {PodTarget} for each spec.
#
# @param [Hash{Podfile::TargetDefinition => Array<ResolvedSpecification>}] resolver_specs_by_target
# @param [Hash{TargetDefinition => Array<ResolvedSpecification>}] resolver_specs_by_target
# the resolved specifications grouped by target.
#
# @param [Hash{TargetDefinition => TargetInspectionResult}] target_inspections
Expand Down Expand Up @@ -671,23 +672,26 @@ def compute_pod_target_dependencies(pod_targets, all_specs)
end

pod_targets.each do |target|
dependencies = dependencies_for_specs(target.library_specs.to_set, target.platform, all_specs).group_by(&:root)
target.dependent_targets = filter_dependencies(dependencies, pod_targets_by_name, target)
target.test_dependent_targets_by_spec_name = target.test_specs.each_with_object({}) do |test_spec, hash|
test_dependencies = dependencies_for_specs([test_spec], target.platform, all_specs).group_by(&:root)
test_dependencies.delete_if { |k, _| dependencies.key? k }
hash[test_spec.name] = filter_dependencies(test_dependencies, pod_targets_by_name, target)
dependencies_by_config = dependencies_for_specs(target.library_specs, target.platform, all_specs)
target.dependent_targets_by_config = Hash[dependencies_by_config.map { |k, v| [k, filter_dependencies(v, pod_targets_by_name, target)] }]

target.test_dependent_targets_by_spec_name_by_config = target.test_specs.each_with_object({}) do |test_spec, hash|
test_dependencies_by_config = dependencies_for_specs([test_spec], target.platform, all_specs)
test_dependencies_by_config.each { |config, deps| deps.delete_if { |k, _| dependencies_by_config[config].key? k } }
hash[test_spec.name] = Hash[test_dependencies_by_config.map { |k, v| [k, filter_dependencies(v, pod_targets_by_name, target)] }]
end

target.app_dependent_targets_by_spec_name = target.app_specs.each_with_object({}) do |app_spec, hash|
app_dependencies = dependencies_for_specs([app_spec], target.platform, all_specs).group_by(&:root)
app_dependencies.delete_if { |k, _| dependencies.key? k }
hash[app_spec.name] = filter_dependencies(app_dependencies, pod_targets_by_name, target)
target.app_dependent_targets_by_spec_name_by_config = target.app_specs.each_with_object({}) do |app_spec, hash|
app_dependencies_by_config = dependencies_for_specs([app_spec], target.platform, all_specs)
app_dependencies_by_config.each { |config, deps| deps.delete_if { |k, _| dependencies_by_config[config].key? k } }
hash[app_spec.name] = Hash[app_dependencies_by_config.map { |k, v| [k, filter_dependencies(v, pod_targets_by_name, target)] }]
end

target.test_app_hosts_by_spec_name = target.test_specs.each_with_object({}) do |test_spec, hash|
next unless app_host_name = test_spec.consumer(target.platform).app_host_name
app_host_spec = pod_targets_by_name[Specification.root_name(app_host_name)].flat_map(&:app_specs).find { |pt| pt.name == app_host_name }
app_host_spec = pod_targets_by_name[Specification.root_name(app_host_name)].flat_map(&:app_specs).find do |pt|
pt.name == app_host_name
end
app_host_dependencies = { app_host_spec.root => [app_host_spec] }
hash[test_spec.name] = [app_host_spec, filter_dependencies(app_host_dependencies, pod_targets_by_name, target).first]
end
Expand Down Expand Up @@ -716,32 +720,39 @@ def filter_dependencies(dependencies, pod_targets_by_name, target)
# @param [Platform] platform
# The platform for which the dependencies should be returned.
#
# @param [Hash<String, Specification>] all_specs
# @param [Hash{String => Array<Specification>}] all_specs
# All specifications which are installed alongside.
#
# @return [Array<Specification>]
# @return [Hash{Symbol => Set<Specification>}]
#
def dependencies_for_specs(specs, platform, all_specs)
return [] if specs.empty? || all_specs.empty?

dependent_specs = Set.new
dependent_specs = {
:debug => Set.new,
:release => Set.new,
}

if !specs.empty? && !all_specs.empty?
specs.each do |s|
s.dependencies(platform).each do |dep|
all_specs[dep.name].each do |spec|
if spec.non_library_specification?
if s.test_specification? && spec.name == s.consumer(platform).app_host_name && spec.app_specification?
# This needs to be handled separately, since we _don't_ want to treat this as a "normal" dependency
next
end
raise Informative, "`#{s}` depends upon `#{spec}`, which is a `#{spec.spec_type}` spec."
end

specs.each do |s|
s.dependencies(platform).each do |dep|
all_specs[dep.name].each do |spec|
if spec.non_library_specification?
if s.test_specification? && spec.name == s.consumer(platform).app_host_name && spec.app_specification?
# This needs to be handled separately, since we _don't_ want to treat this as a "normal" dependency
next
dependent_specs.each do |config, set|
next unless s.dependency_whitelisted_for_configuration?(dep, config)
set << spec
end
raise Informative, "#{s} depends upon `#{spec}`, which is a `#{spec.spec_type}` spec."
end
dependent_specs << spec
end
end
end

dependent_specs - specs
Hash[dependent_specs.map { |k, v| [k, (v - specs).group_by(&:root)] }].freeze
end

# Create a target for each spec group
Expand Down Expand Up @@ -779,7 +790,9 @@ def generate_pod_target(target_definitions, build_type, target_inspections, spec
target_inspections.flat_map(&:archs).compact.uniq.sort
end
else
user_build_configurations = Target::DEFAULT_BUILD_CONFIGURATIONS
user_build_configurations = Target::DEFAULT_BUILD_CONFIGURATIONS.merge(
target_definitions.map { |td| td.build_configurations || {} }.reduce({}, &:merge),
)
archs = target_requires_64_bit ? ['$(ARCHS_STANDARD_64_BIT)'] : []
end
platform = determine_platform(specs, target_definitions, build_type)
Expand Down
12 changes: 7 additions & 5 deletions lib/cocoapods/installer/project_cache/target_cache_key.rb
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,14 @@ def self.from_cache_hash(sandbox, key_hash)
#
def self.from_pod_target(sandbox, pod_target, is_local_pod: false, checkout_options: nil)
build_settings = {}
build_settings[pod_target.label.to_s] = Digest::MD5.hexdigest(pod_target.build_settings.xcconfig.to_s)
pod_target.test_spec_build_settings.each do |name, settings|
build_settings[name] = Digest::MD5.hexdigest(settings.xcconfig.to_s)
build_settings[pod_target.label.to_s] = Hash[pod_target.build_settings.map do |k, v|
[k, Digest::MD5.hexdigest(v.xcconfig.to_s)]
end]
pod_target.test_spec_build_settings_by_config.each do |name, settings_by_config|
build_settings[name] = Hash[settings_by_config.map { |k, v| [k, Digest::MD5.hexdigest(v.xcconfig.to_s)] }]
end
pod_target.app_spec_build_settings.each do |name, settings|
build_settings[name] = Digest::MD5.hexdigest(settings.xcconfig.to_s)
pod_target.app_spec_build_settings_by_config.each do |name, settings_by_config|
build_settings[name] = Hash[settings_by_config.map { |k, v| [k, Digest::MD5.hexdigest(v.xcconfig.to_s)] }]
end

contents = {
Expand Down
Loading

0 comments on commit 2db4a0a

Please sign in to comment.