Skip to content

Commit

Permalink
Integrate ODR categories into projects.
Browse files Browse the repository at this point in the history
  • Loading branch information
dnkoutso committed Aug 10, 2021
1 parent 22a6218 commit dbdd879
Show file tree
Hide file tree
Showing 13 changed files with 179 additions and 55 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Expand Up @@ -8,7 +8,9 @@ To install release candidates run `[sudo] gem install cocoapods --pre`

##### Enhancements

* None.
* Integrate ODR categories into projects.
[Dimitris Koutsogiorgas](https://github.com/dnkoutso)
[#10855](https://github.com/CocoaPods/CocoaPods/pull/10855)

##### Bug Fixes

Expand Down
2 changes: 1 addition & 1 deletion Gemfile.lock
Expand Up @@ -7,7 +7,7 @@ GIT

GIT
remote: https://github.com/CocoaPods/Core.git
revision: 609a964026350b86d4c5bf9a30c03c1c699be32c
revision: bdfd495cc11162f2e82da157116024ac51d05f4c
branch: 1-11-stable
specs:
cocoapods-core (1.11.0.beta.1)
Expand Down
Expand Up @@ -404,6 +404,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
ON_DEMAND_RESOURCES_PREFETCH_ORDER = t2;
PRODUCT_BUNDLE_IDENTIFIER = com.junyixie..OnDemandResourcesDemo;
PRODUCT_NAME = "$(TARGET_NAME)";
TARGETED_DEVICE_FAMILY = "1,2";
Expand All @@ -421,6 +422,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
ON_DEMAND_RESOURCES_PREFETCH_ORDER = t2;
PRODUCT_BUNDLE_IDENTIFIER = com.junyixie..OnDemandResourcesDemo;
PRODUCT_NAME = "$(TARGET_NAME)";
TARGETED_DEVICE_FAMILY = "1,2";
Expand Down
Expand Up @@ -36,7 +36,7 @@ TODO: Add long description of the pod here.

s.on_demand_resources = {
't1' => ['on_demand_bundle1/*'],
't2' => ['on_demand_bundle2/*']
't2' => { :paths => ['on_demand_bundle2/*'], :category => :prefetched },
}

s.pod_target_xcconfig = {
Expand All @@ -47,15 +47,15 @@ TODO: Add long description of the pod here.
app_spec.source_files = 'App1/Classes/**/*'

app_spec.on_demand_resources = {
'a1' => ['App1/app1_on_demand_bundle1/*']
'a1' => { :paths => ['App1/app1_on_demand_bundle1/*'], :category => :initial_install }
}
end

s.app_spec 'App2' do |app_spec|
app_spec.source_files = 'App2/Classes/**/*'

app_spec.on_demand_resources = {
'a2' => ['App2/app2_on_demand_bundle1/*']
'a2' => { :paths => ['App2/app2_on_demand_bundle1/*'], :category => :initial_install }
}
end

Expand Down
7 changes: 5 additions & 2 deletions lib/cocoapods/installer/project_cache/target_cache_key.rb
Expand Up @@ -162,8 +162,11 @@ def self.from_aggregate_target(sandbox, aggregate_target)
'BUILD_SETTINGS_CHECKSUM' => build_settings,
}
if aggregate_target.includes_resources? || aggregate_target.includes_on_demand_resources?
relative_file_paths = aggregate_target.resource_paths_by_config.values.flatten.uniq + aggregate_target.on_demand_resources.map(&:to_s)
contents['FILES'] = relative_file_paths.sort_by(&:downcase)
relative_resource_file_paths = aggregate_target.resource_paths_by_config.values.flatten.uniq
relative_on_demand_resource_file_paths = aggregate_target.on_demand_resources.map do |res|
res.relative_path_from(sandbox.project_path.dirname).to_s
end
contents['FILES'] = (relative_resource_file_paths + relative_on_demand_resource_file_paths).sort_by(&:downcase)
end
TargetCacheKey.new(sandbox, :aggregate, contents)
end
Expand Down
Expand Up @@ -459,7 +459,7 @@ def embed_frameworks_output_paths(framework_paths, xcframeworks)
#
def add_on_demand_resources(sandbox, project, native_targets, file_accessors, parent_odr_group,
target_odr_group_name)
asset_tags_added = Set.new
category_to_tags = {}
file_accessors = Array(file_accessors)
native_targets = Array(native_targets)

Expand All @@ -469,8 +469,8 @@ def add_on_demand_resources(sandbox, project, native_targets, file_accessors, pa
old_odr_file_refs = old_target_odr_group&.recursive_children_groups&.each_with_object({}) do |group, hash|
hash[group.name] = group.files
end || {}
native_targets.each do |user_target|
user_target.remove_on_demand_resources(old_odr_file_refs)
native_targets.each do |native_target|
native_target.remove_on_demand_resources(old_odr_file_refs)
end
old_target_odr_group&.remove_from_project
return
Expand All @@ -480,17 +480,18 @@ def add_on_demand_resources(sandbox, project, native_targets, file_accessors, pa
current_file_refs = target_odr_group.recursive_children_groups.flat_map(&:files)

added_file_refs = file_accessors.flat_map do |file_accessor|
target_odr_files_refs = Hash[file_accessor.on_demand_resources.map do |tag, resources|
target_odr_files_refs = Hash[file_accessor.on_demand_resources.map do |tag, value|
tag_group = target_odr_group[tag] || target_odr_group.new_group(tag)
asset_tags_added << tag
resources_file_refs = resources.map do |resource|
category_to_tags[value[:category]] ||= []
category_to_tags[value[:category]] << tag
resources_file_refs = value[:paths].map do |resource|
odr_resource_file_ref = Pathname.new(resource).relative_path_from(sandbox.root)
tag_group.find_file_by_path(odr_resource_file_ref.to_s) || tag_group.new_file(odr_resource_file_ref)
end
[tag, resources_file_refs]
end]
native_targets.each do |user_target|
user_target.add_on_demand_resources(target_odr_files_refs)
native_targets.each do |native_target|
native_target.add_on_demand_resources(target_odr_files_refs)
end
target_odr_files_refs.values.flatten
end
Expand All @@ -506,10 +507,34 @@ def add_on_demand_resources(sandbox, project, native_targets, file_accessors, pa
end
target_odr_group.recursive_children_groups.each { |g| g.remove_from_project if g.empty? }

unless asset_tags_added.empty?
attributes = project.root_object.attributes
attributes['KnownAssetTags'] = (attributes['KnownAssetTags'] ||= []) | asset_tags_added.to_a
project.root_object.attributes = attributes
attributes = project.root_object.attributes
attributes['KnownAssetTags'] = (attributes['KnownAssetTags'] ||= []) | category_to_tags.values.flatten
project.root_object.attributes = attributes

%w[ON_DEMAND_RESOURCES_INITIAL_INSTALL_TAGS ON_DEMAND_RESOURCES_PREFETCH_ORDER].each do |category_key|
native_targets.each do |native_target|
native_target.build_configurations.each do |c|
key = case category_key
when 'ON_DEMAND_RESOURCES_INITIAL_INSTALL_TAGS'
:initial_install
when 'ON_DEMAND_RESOURCES_PREFETCH_ORDER'
:prefetched
else
:download_on_demand
end
tags_for_category = (c.build_settings[category_key] || '').split
category_to_tags_dup = category_to_tags.dup
tags_to_add = category_to_tags_dup.delete(key) || []
tags_to_delete = category_to_tags_dup.values.flatten
tags_for_category = (tags_for_category + tags_to_add - tags_to_delete).flatten.compact.uniq
if tags_for_category.empty?
c.build_settings.delete(category_key)
else
c.build_settings[category_key] = tags_for_category.join(' ')
end
native_target.project.mark_dirty!
end
end
end
end
end
Expand Down
16 changes: 11 additions & 5 deletions lib/cocoapods/sandbox/file_accessor.rb
Expand Up @@ -219,7 +219,7 @@ def self.all_files(file_accessors)
file_accessors.map(&:preserve_paths),
file_accessors.map(&:readme),
file_accessors.map(&:resources),
file_accessors.flat_map { |f| f.on_demand_resources.values.flatten },
file_accessors.map(&:on_demand_resources_files),
file_accessors.map(&:source_files),
file_accessors.map(&:module_map),
]
Expand Down Expand Up @@ -334,20 +334,26 @@ def resource_bundle_files
resource_bundles.values.flatten
end

# @return [Hash{String => Array<Pathname>}] The paths of the on demand resources specified
# keyed by their tag.
# @return [Hash{String => Hash] The expanded paths of the on demand resources specified
# keyed by their tag including their category.
#
def on_demand_resources
result = {}
spec_consumer.on_demand_resources.each do |tag_name, file_patterns|
paths = expanded_paths(file_patterns,
paths = expanded_paths(file_patterns[:paths],
:exclude_patterns => spec_consumer.exclude_files,
:include_dirs => true)
result[tag_name] = paths
result[tag_name] = { :paths => paths, :category => file_patterns[:category] }
end
result
end

# @return [Array<Pathname>] The expanded paths of the on demand resources.
#
def on_demand_resources_files
on_demand_resources.values.flat_map { |v| v[:paths] }
end

# @return [Pathname] The of the prefix header file of the specification.
#
def prefix_header
Expand Down
2 changes: 1 addition & 1 deletion lib/cocoapods/target/aggregate_target.rb
Expand Up @@ -288,7 +288,7 @@ def on_demand_resources
@on_demand_resources ||= begin
pod_targets.flat_map do |pod_target|
library_file_accessors = pod_target.file_accessors.select { |fa| fa.spec.library_specification? }
library_file_accessors.flat_map { |fa| fa.on_demand_resources.values.flatten }
library_file_accessors.flat_map(&:on_demand_resources_files)
end.uniq
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/cocoapods/target/pod_target.rb
Expand Up @@ -203,7 +203,7 @@ def label
end
end

# @return [Array<String>] The list of all files tracked.
# @return [Array<Pathname>] The list of all files tracked.
#
def all_files
Sandbox::FileAccessor.all_files(file_accessors)
Expand Down
14 changes: 10 additions & 4 deletions spec/unit/installer/project_cache/target_cache_key_spec.rb
Expand Up @@ -38,20 +38,26 @@ module ProjectCache
fixture_target_definition('MyApp'), config.sandbox.root.dirname, nil,
nil, 'Debug' => [@banana_pod_target])
@banana_pod_target.stubs(:resource_paths).returns({})
@banana_pod_target.file_accessors.first.stubs(:on_demand_resources).returns('tag1' => ['/path/to/resource'])
on_demand_resources = { 'tag1' => { :paths => [Pathname('/path/to/resource')], :category => :download_on_demand } }
@banana_pod_target.file_accessors.first.stubs(:on_demand_resources).returns(on_demand_resources)
aggregate_target_cache_key = TargetCacheKey.from_aggregate_target(config.sandbox, aggregate_target)
library_on_demand_resources = @banana_pod_target.file_accessors.first.on_demand_resources.values.flatten.sort_by(&:downcase)
library_on_demand_resources = @banana_pod_target.file_accessors.first.on_demand_resources_files.map do |p|
p.relative_path_from(config.sandbox.root).to_s.downcase
end
aggregate_target_cache_key.to_h['FILES'].should.equal(library_on_demand_resources)
end

it 'should output files for aggregate target if it has aggregate both aggregate resources and on demand resources' do
aggregate_target = AggregateTarget.new(config.sandbox, BuildType.static_library, { 'Debug' => :debug }, [], Platform.ios,
fixture_target_definition('MyApp'), config.sandbox.root.dirname, nil,
nil, 'Debug' => [@banana_pod_target])
@banana_pod_target.file_accessors.first.stubs(:on_demand_resources).returns('tag1' => ['/path/to/resource'])
on_demand_resources = { 'tag1' => { :paths => [Pathname('/path/to/resource')], :category => :download_on_demand } }
@banana_pod_target.file_accessors.first.stubs(:on_demand_resources).returns(on_demand_resources)
aggregate_target_cache_key = TargetCacheKey.from_aggregate_target(config.sandbox, aggregate_target)
library_resources = @banana_pod_target.resource_paths.values.flatten.sort_by(&:downcase)
library_on_demand_resources = @banana_pod_target.file_accessors.first.on_demand_resources.values.flatten.sort_by(&:downcase)
library_on_demand_resources = @banana_pod_target.file_accessors.first.on_demand_resources_files.map do |p|
p.relative_path_from(config.sandbox.root).to_s.downcase
end
aggregate_target_cache_key.to_h['FILES'].should.equal(library_resources + library_on_demand_resources)
end
end
Expand Down
Expand Up @@ -754,9 +754,8 @@ module Pod
end

it 'adds and remove on demand resources to the user target resources build phase' do
@banana_pod_target.file_accessors.first.stubs(:on_demand_resources).returns(
'tag1' => [config.sandbox.root + 'banana-lib/path/to/resource.png'],
)
on_demand_resources = { 'tag1' => { :paths => [config.sandbox.root + 'banana-lib/path/to/resource.png'], :category => :download_on_demand } }
@banana_pod_target.file_accessors.first.stubs(:on_demand_resources).returns(on_demand_resources)
@target_integrator.integrate!
target = @target_integrator.send(:native_targets).first
target.resources_build_phase.files.map(&:display_name).should == ['InfoPlist.strings', 'resource.png']
Expand All @@ -776,10 +775,11 @@ module Pod
end

it 'removes stale on demand resource file references' do
@banana_pod_target.file_accessors.first.stubs(:on_demand_resources).returns(
'tag1' => [config.sandbox.root + 'banana-lib/path/to/resource.png'],
'tag2' => [config.sandbox.root + 'banana-lib/path/to/resource2.png'],
)
on_demand_resources = {
'tag1' => { :paths => [config.sandbox.root + 'banana-lib/path/to/resource.png'], :category => :download_on_demand },
'tag2' => { :paths => [config.sandbox.root + 'banana-lib/path/to/resource2.png'], :category => :download_on_demand },
}
@banana_pod_target.file_accessors.first.stubs(:on_demand_resources).returns(on_demand_resources)
@target_integrator.integrate!
target = @target_integrator.send(:native_targets).first
target.resources_build_phase.files.map(&:display_name).should == ['InfoPlist.strings', 'resource.png', 'resource2.png']
Expand All @@ -789,9 +789,8 @@ module Pod
@project['Pods']['BananaLib-OnDemandResources']['tag1'].files.map(&:display_name).should == ['resource.png']
@project['Pods']['BananaLib-OnDemandResources']['tag2'].files.map(&:display_name).should == ['resource2.png']
@project.root_object.attributes['KnownAssetTags'].should == %w[tag1 tag2]
@banana_pod_target.file_accessors.first.stubs(:on_demand_resources).returns(
'tag2' => [config.sandbox.root + 'banana-lib/path/to/resource2.png'],
)
on_demand_resources = { 'tag2' => { :paths => [config.sandbox.root + 'banana-lib/path/to/resource2.png'], :category => :download_on_demand } }
@banana_pod_target.file_accessors.first.stubs(:on_demand_resources).returns(on_demand_resources)
@target_integrator.integrate!
target.resources_build_phase.files.map(&:display_name).should == ['InfoPlist.strings', 'resource2.png']
@project.main_group.find_subpath('Pods/BananaLib-OnDemandResources').should.not.be.nil
Expand All @@ -804,6 +803,64 @@ module Pod
@project.root_object.attributes['KnownAssetTags'].should == %w[tag1 tag2]
end

it 'sets on demand resource category build settings' do
on_demand_resources = {
'tag1' => { :paths => [config.sandbox.root + 'banana-lib/path/to/resource.png'], :category => :initial_install },
'tag2' => { :paths => [config.sandbox.root + 'banana-lib/path/to/resource2.png'], :category => :prefetched },
}
@banana_pod_target.file_accessors.first.stubs(:on_demand_resources).returns(on_demand_resources)
@target_integrator.integrate!
target = @target_integrator.send(:native_targets).first
@project.root_object.attributes['KnownAssetTags'].should == %w[tag1 tag2]
target.build_configurations.each do |bc|
bc.build_settings['ON_DEMAND_RESOURCES_INITIAL_INSTALL_TAGS'].should == 'tag1'
bc.build_settings['ON_DEMAND_RESOURCES_PREFETCH_ORDER'].should == 'tag2'
end
end

it 'sets multiple on demand resource categories on a single build setting' do
on_demand_resources = {
'tag1' => { :paths => [config.sandbox.root + 'banana-lib/path/to/resource.png'], :category => :initial_install },
'tag2' => { :paths => [config.sandbox.root + 'banana-lib/path/to/resource2.png'], :category => :initial_install },
}
@banana_pod_target.file_accessors.first.stubs(:on_demand_resources).returns(on_demand_resources)
@target_integrator.integrate!
target = @target_integrator.send(:native_targets).first
@project.root_object.attributes['KnownAssetTags'].should == %w[tag1 tag2]
target.build_configurations.each do |bc|
bc.build_settings['ON_DEMAND_RESOURCES_INITIAL_INSTALL_TAGS'].should == 'tag1 tag2'
bc.build_settings['ON_DEMAND_RESOURCES_PREFETCH_ORDER'].should.be.nil
end
end

it 'updates on demand resources build settings if they change' do
on_demand_resources = {
'tag1' => { :paths => [config.sandbox.root + 'banana-lib/path/to/resource.png'], :category => :initial_install },
'tag2' => { :paths => [config.sandbox.root + 'banana-lib/path/to/resource2.png'], :category => :initial_install },
'tag3' => { :paths => [config.sandbox.root + 'banana-lib/path/to/resource3.png'], :category => :initial_install },
}
@banana_pod_target.file_accessors.first.stubs(:on_demand_resources).returns(on_demand_resources)
@target_integrator.integrate!
target = @target_integrator.send(:native_targets).first
@project.root_object.attributes['KnownAssetTags'].should == %w[tag1 tag2 tag3]
target.build_configurations.each do |bc|
bc.build_settings['ON_DEMAND_RESOURCES_INITIAL_INSTALL_TAGS'].should == 'tag1 tag2 tag3'
bc.build_settings['ON_DEMAND_RESOURCES_PREFETCH_ORDER'].should.be.nil
end
on_demand_resources = {
'tag1' => { :paths => [config.sandbox.root + 'banana-lib/path/to/resource.png'], :category => :prefetched },
'tag2' => { :paths => [config.sandbox.root + 'banana-lib/path/to/resource2.png'], :category => :initial_install },
'tag3' => { :paths => [config.sandbox.root + 'banana-lib/path/to/resource3.png'], :category => :download_on_demand },
}
@banana_pod_target.file_accessors.first.stubs(:on_demand_resources).returns(on_demand_resources)
@target_integrator.integrate!
@project.root_object.attributes['KnownAssetTags'].should == %w[tag1 tag2 tag3]
target.build_configurations.each do |bc|
bc.build_settings['ON_DEMAND_RESOURCES_INITIAL_INSTALL_TAGS'].should == 'tag2'
bc.build_settings['ON_DEMAND_RESOURCES_PREFETCH_ORDER'].should == 'tag1'
end
end

describe 'Script paths' do
it 'calculates the output paths of the embed frameworks script' do
paths = [
Expand Down

0 comments on commit dbdd879

Please sign in to comment.