cocoapods-bazel 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitattributes +2 -0
- data/.github/workflows/tests.yml +23 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.rubocop.yml +12 -0
- data/.rubocop_todo.yml +26 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +145 -0
- data/LICENSE.txt +201 -0
- data/README.md +53 -0
- data/Rakefile +47 -0
- data/bin/console +15 -0
- data/bin/pod +29 -0
- data/bin/pod_install_bazel_build +26 -0
- data/bin/rake +29 -0
- data/bin/setup +8 -0
- data/cocoapods-bazel.gemspec +35 -0
- data/lib/cocoapods/bazel.rb +112 -0
- data/lib/cocoapods/bazel/config.rb +60 -0
- data/lib/cocoapods/bazel/target.rb +630 -0
- data/lib/cocoapods/bazel/util.rb +34 -0
- data/lib/cocoapods/bazel/version.rb +7 -0
- data/lib/cocoapods/bazel/xcconfig_resolver.rb +65 -0
- data/lib/cocoapods_plugin.rb +24 -0
- metadata +103 -0
data/README.md
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# Cocoapods::Bazel
|
2
|
+

|
3
|
+
|
4
|
+
|
5
|
+
Cocoapods::Bazel is a Cocoapods plugin that makes it easy to use [Bazel](https://bazel.build) instead of Xcode to build your iOS project. It automatically generates Bazel's `BUILD.bazel` files. It uses [`rules_ios`](https://github.com/ob/rules_ios) so you need to set up the `WORKSPACE` file following the instructions in the [`README`](https://github.com/ob/rules_ios/blob/master/README.md).
|
6
|
+
|
7
|
+
> :warning: **This is alpha software.** We are developing this plugin in the open so you should only use it if you know what you are doing and are willing to help develop it.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
gem 'cocoapods-bazel'
|
15
|
+
```
|
16
|
+
|
17
|
+
And then execute:
|
18
|
+
|
19
|
+
$ bundle
|
20
|
+
|
21
|
+
Or install it yourself as:
|
22
|
+
|
23
|
+
$ gem install cocoapods-bazel
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
This plugin will run extra steps after post_install to generate BUILD.bazel files for Bazel.
|
28
|
+
|
29
|
+
To enable the plugin, simply add the following section to your `Podfile`
|
30
|
+
|
31
|
+
```
|
32
|
+
plugin 'cocoapods-bazel', {
|
33
|
+
rules: {
|
34
|
+
'apple_framework' => { load: '@build_bazel_rules_ios//rules:framework.bzl', rule: 'apple_framework' }.freeze,
|
35
|
+
'ios_application' => { load: '@build_bazel_rules_ios//rules:app.bzl', rule: 'ios_application' }.freeze,
|
36
|
+
'ios_unit_test' => { load: '@build_bazel_rules_ios//rules:test.bzl', rule: 'ios_unit_test' }.freeze
|
37
|
+
}.freeze,
|
38
|
+
}
|
39
|
+
```
|
40
|
+
|
41
|
+
## Development
|
42
|
+
|
43
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
44
|
+
|
45
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
46
|
+
|
47
|
+
## Contributing
|
48
|
+
|
49
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/ob/cocoapods-bazel.
|
50
|
+
|
51
|
+
## License
|
52
|
+
|
53
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
require 'rubocop/rake_task'
|
6
|
+
|
7
|
+
namespace :spec do
|
8
|
+
RSpec::Core::RakeTask.new(:unit) do |t|
|
9
|
+
t.rspec_opts = %w[--format progress]
|
10
|
+
end
|
11
|
+
|
12
|
+
desc 'Run integration specs'
|
13
|
+
task :integration do
|
14
|
+
sh 'bundle', 'exec', 'bacon', 'spec/integration.rb', '-q'
|
15
|
+
end
|
16
|
+
|
17
|
+
namespace :integration do
|
18
|
+
desc 'Update integration spec fixtures'
|
19
|
+
task :update do
|
20
|
+
rm_rf 'spec/integration/tmp'
|
21
|
+
sh('bin/rake', 'spec:integration') {}
|
22
|
+
# Copy the files to the files produced by the specs to the after folders
|
23
|
+
FileList['spec/integration/tmp/*/transformed'].each do |source|
|
24
|
+
walk_dir = lambda do |d|
|
25
|
+
Dir.each_child(d) do |c|
|
26
|
+
child = File.join(d, c)
|
27
|
+
walk_dir[child] if File.directory?(child)
|
28
|
+
end
|
29
|
+
Dir.delete(d) if Dir.empty?(d)
|
30
|
+
end
|
31
|
+
walk_dir[source]
|
32
|
+
|
33
|
+
name = source.match(%r{tmp/([^/]+)/transformed$})[1]
|
34
|
+
destination = "spec/integration/#{name}/after"
|
35
|
+
rm_rf destination
|
36
|
+
mv source, destination
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
desc 'Run all specs'
|
43
|
+
task spec: %w[spec:unit spec:integration]
|
44
|
+
|
45
|
+
RuboCop::RakeTask.new(:rubocop)
|
46
|
+
|
47
|
+
task default: %i[spec rubocop]
|
data/bin/console
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'cocoapods/bazel'
|
6
|
+
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
9
|
+
|
10
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
11
|
+
# require "pry"
|
12
|
+
# Pry.start
|
13
|
+
|
14
|
+
require 'irb'
|
15
|
+
IRB.start(__FILE__)
|
data/bin/pod
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'pod' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require 'pathname'
|
12
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path('bundle', __dir__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require 'rubygems'
|
27
|
+
require 'bundler/setup'
|
28
|
+
|
29
|
+
load Gem.bin_path('cocoapods', 'pod')
|
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'pathname'
|
5
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
|
6
|
+
Pathname.new(__FILE__).realpath)
|
7
|
+
|
8
|
+
bundle_binstub = File.expand_path('bundle', __dir__)
|
9
|
+
|
10
|
+
if File.file?(bundle_binstub)
|
11
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
12
|
+
load(bundle_binstub)
|
13
|
+
else
|
14
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
15
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
require 'rubygems'
|
20
|
+
require 'bundler/setup'
|
21
|
+
|
22
|
+
ARGV.replace %w[install]
|
23
|
+
|
24
|
+
load Gem.bin_path('cocoapods', 'pod')
|
25
|
+
|
26
|
+
exec 'bazelisk', '--ignore_all_rc_files', 'build', '--verbose_failures', '...'
|
data/bin/rake
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'rake' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require 'pathname'
|
12
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path('bundle', __dir__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require 'rubygems'
|
27
|
+
require 'bundler/setup'
|
28
|
+
|
29
|
+
load Gem.bin_path('rake', 'rake')
|
data/bin/setup
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lib/cocoapods/bazel/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'cocoapods-bazel'
|
7
|
+
spec.version = Pod::Bazel::VERSION
|
8
|
+
spec.authors = ['Shawn Chen', 'Samuel Giddins']
|
9
|
+
spec.email = ['swchen@linkedin.com', 'segiddins@squareup.com']
|
10
|
+
|
11
|
+
spec.summary = 'A plugin for CocoaPods that generates Bazel build files for pods'
|
12
|
+
spec.homepage = 'https://github.com/ob/cocoapods-bazel'
|
13
|
+
spec.license = 'apache2'
|
14
|
+
|
15
|
+
spec.metadata['allowed_push_host'] = "https://rubygems.org/"
|
16
|
+
|
17
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
18
|
+
spec.metadata['source_code_uri'] = spec.homepage
|
19
|
+
spec.metadata['changelog_uri'] = "#{spec.homepage}/blob/master/CHANGELOG.md"
|
20
|
+
|
21
|
+
# Specify which files should be added to the gem when it is released.
|
22
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
23
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
24
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
25
|
+
end
|
26
|
+
spec.bindir = 'exe'
|
27
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
28
|
+
spec.require_paths = ['lib']
|
29
|
+
|
30
|
+
spec.add_development_dependency 'bundler', '>= 2.1'
|
31
|
+
|
32
|
+
spec.add_runtime_dependency 'starlark_compiler', '~> 0.3'
|
33
|
+
|
34
|
+
spec.required_ruby_version = '>= 2.6'
|
35
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'starlark_compiler/build_file'
|
4
|
+
require 'cocoapods/bazel/config'
|
5
|
+
require 'cocoapods/bazel/target'
|
6
|
+
require 'cocoapods/bazel/xcconfig_resolver'
|
7
|
+
require 'cocoapods/bazel/util'
|
8
|
+
|
9
|
+
module Pod
|
10
|
+
module Bazel
|
11
|
+
def self.post_install(installer:)
|
12
|
+
return unless (config = Config.from_podfile(installer.podfile))
|
13
|
+
|
14
|
+
default_xcconfigs = config.default_xcconfigs.transform_values do |xcconfig|
|
15
|
+
_name, xcconfig = XCConfigResolver.resolve_xcconfig(xcconfig)
|
16
|
+
xcconfig
|
17
|
+
end
|
18
|
+
|
19
|
+
UI.titled_section 'Generating Bazel files' do
|
20
|
+
workspace = installer.config.installation_root
|
21
|
+
sandbox = installer.sandbox
|
22
|
+
build_files = Hash.new { |h, k| h[k] = StarlarkCompiler::BuildFile.new(workspace: workspace, package: k) }
|
23
|
+
installer.pod_targets.each do |pod_target|
|
24
|
+
package = sandbox.pod_dir(pod_target.pod_name).relative_path_from(workspace).to_s
|
25
|
+
if package.start_with?('..')
|
26
|
+
raise Informative, <<~MSG
|
27
|
+
Bazel does not support Pod located outside of current workspace: \"#{package}\".
|
28
|
+
To fix this, you can move the Pod into workspace,
|
29
|
+
or you can symlink the Pod inside the workspace by running `ln -s <path_to_pod> .` at workspace root
|
30
|
+
Then change path declared in Podfile to `./<pod_name>`
|
31
|
+
Current workspace: #{workspace}
|
32
|
+
MSG
|
33
|
+
end
|
34
|
+
|
35
|
+
build_file = build_files[package]
|
36
|
+
|
37
|
+
bazel_targets = [Target.new(installer, pod_target, nil, default_xcconfigs)] +
|
38
|
+
pod_target.file_accessors.reject { |fa| fa.spec.library_specification? }.map { |fa| Target.new(installer, pod_target, fa.spec, default_xcconfigs) }
|
39
|
+
|
40
|
+
bazel_targets.each do |t|
|
41
|
+
load = config.load_for(macro: t.type)
|
42
|
+
build_file.add_load(of: load[:rule], from: load[:load])
|
43
|
+
build_file.add_target StarlarkCompiler::AST::FunctionCall.new(load[:rule], **t.to_rule_kwargs)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
build_files.each_value(&:save!)
|
48
|
+
format_files(build_files: build_files, buildifier: config.buildifier, workspace: workspace)
|
49
|
+
|
50
|
+
cocoapods_bazel_path = File.join(sandbox.root, 'cocoapods-bazel')
|
51
|
+
FileUtils.mkdir_p cocoapods_bazel_path
|
52
|
+
|
53
|
+
write_cocoapods_bazel_build_file(cocoapods_bazel_path, workspace, config)
|
54
|
+
write_non_empty_default_xcconfigs(cocoapods_bazel_path, default_xcconfigs)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.write_cocoapods_bazel_build_file(path, workspace, config)
|
59
|
+
FileUtils.touch(File.join(path, 'BUILD.bazel'))
|
60
|
+
|
61
|
+
cocoapods_bazel_pkg = Pathname.new(path).relative_path_from Pathname.new(workspace)
|
62
|
+
configs_build_file = StarlarkCompiler::BuildFile.new(workspace: workspace, package: cocoapods_bazel_pkg)
|
63
|
+
|
64
|
+
configs_build_file.add_load(of: 'string_flag', from: '@bazel_skylib//rules:common_settings.bzl')
|
65
|
+
configs_build_file.add_target StarlarkCompiler::AST::FunctionCall.new('string_flag', name: 'config', build_setting_default: 'debug', visibility: ['//visibility:public'])
|
66
|
+
configs_build_file.add_target StarlarkCompiler::AST::FunctionCall.new('config_setting', name: 'debug', flag_values: { ':config' => 'debug' })
|
67
|
+
configs_build_file.add_target StarlarkCompiler::AST::FunctionCall.new('config_setting', name: 'release', flag_values: { ':config' => 'release' })
|
68
|
+
|
69
|
+
configs_build_file.save!
|
70
|
+
format_files(build_files: { cocoapods_bazel_pkg => configs_build_file }, buildifier: config.buildifier, workspace: workspace)
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.write_non_empty_default_xcconfigs(path, default_xcconfigs)
|
74
|
+
return if default_xcconfigs.empty?
|
75
|
+
|
76
|
+
hash = StarlarkCompiler::AST.new(toplevel: [StarlarkCompiler::AST::Dictionary.new(default_xcconfigs)])
|
77
|
+
|
78
|
+
File.open(File.join(path, 'default_xcconfigs.bzl'), 'w') do |f|
|
79
|
+
f << <<~STARLARK
|
80
|
+
"""
|
81
|
+
Default xcconfigs given as options to cocoapods-bazel.
|
82
|
+
"""
|
83
|
+
|
84
|
+
STARLARK
|
85
|
+
f << 'DEFAULT_XCCONFIGS = '
|
86
|
+
StarlarkCompiler::Writer.write(ast: hash, io: f)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.format_files(build_files:, buildifier:, workspace:)
|
91
|
+
return if build_files.empty?
|
92
|
+
|
93
|
+
args = []
|
94
|
+
case buildifier
|
95
|
+
when true
|
96
|
+
return unless Pod::Executable.which('buildifier')
|
97
|
+
|
98
|
+
args = ['buildifier']
|
99
|
+
when String, Array
|
100
|
+
args = Array(buildifier)
|
101
|
+
else
|
102
|
+
return
|
103
|
+
end
|
104
|
+
args += %w[-type build]
|
105
|
+
|
106
|
+
executable, *args = args
|
107
|
+
Pod::Executable.execute_command executable,
|
108
|
+
args + build_files.each_key.map { |d| File.join workspace, d, 'BUILD.bazel' },
|
109
|
+
true
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Pod
|
4
|
+
module Bazel
|
5
|
+
class Config
|
6
|
+
PLUGIN_KEY = 'cocoapods-bazel'
|
7
|
+
private_constant :PLUGIN_KEY
|
8
|
+
DEFAULTS = {
|
9
|
+
rules: {
|
10
|
+
'apple_framework' => { load: '@build_bazel_rules_ios//rules:framework.bzl', rule: 'apple_framework' }.freeze,
|
11
|
+
'ios_application' => { load: '@build_bazel_rules_ios//rules:app.bzl', rule: 'ios_application' }.freeze,
|
12
|
+
'ios_unit_test' => { load: '@build_bazel_rules_ios//rules:test.bzl', rule: 'ios_unit_test' }.freeze
|
13
|
+
}.freeze,
|
14
|
+
overrides: {}.freeze,
|
15
|
+
buildifier: true,
|
16
|
+
default_xcconfigs: {}.freeze
|
17
|
+
}.with_indifferent_access.freeze
|
18
|
+
private_constant :DEFAULTS
|
19
|
+
|
20
|
+
attr_reader :to_h
|
21
|
+
|
22
|
+
def self.enabled_in_podfile?(podfile)
|
23
|
+
podfile.plugins.key?(PLUGIN_KEY)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.from_podfile(podfile)
|
27
|
+
return unless enabled_in_podfile?(podfile)
|
28
|
+
|
29
|
+
from_podfile_options(podfile.plugins[PLUGIN_KEY])
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.from_podfile_options(options)
|
33
|
+
new(DEFAULTS.merge(options) do |_key, old_val, new_val|
|
34
|
+
case old_val
|
35
|
+
when Hash
|
36
|
+
old_val.merge(new_val) # intentionally only 1 level deep of merging
|
37
|
+
else
|
38
|
+
new_val
|
39
|
+
end
|
40
|
+
end)
|
41
|
+
end
|
42
|
+
|
43
|
+
def initialize(to_h)
|
44
|
+
@to_h = to_h
|
45
|
+
end
|
46
|
+
|
47
|
+
def buildifier
|
48
|
+
to_h[:buildifier]
|
49
|
+
end
|
50
|
+
|
51
|
+
def load_for(macro:)
|
52
|
+
to_h.dig('rules', macro) || raise("no rule configured for #{macro}")
|
53
|
+
end
|
54
|
+
|
55
|
+
def default_xcconfigs
|
56
|
+
to_h[:default_xcconfigs]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,630 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'xcconfig_resolver'
|
4
|
+
|
5
|
+
module Pod
|
6
|
+
module Bazel
|
7
|
+
class Target
|
8
|
+
class RuleArgs
|
9
|
+
attr_reader :kwargs
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@kwargs = {}
|
13
|
+
|
14
|
+
yield self if block_given?
|
15
|
+
end
|
16
|
+
|
17
|
+
def add(name, value, defaults: nil)
|
18
|
+
return self if defaults&.include?(value)
|
19
|
+
|
20
|
+
raise 'Duplicate' if kwargs.key?(name)
|
21
|
+
|
22
|
+
kwargs[name] = value
|
23
|
+
|
24
|
+
self
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
include XCConfigResolver
|
29
|
+
|
30
|
+
attr_reader :installer, :pod_target, :file_accessors, :non_library_spec, :label, :package, :default_xcconfigs, :resolved_xconfig_by_config
|
31
|
+
private :installer, :pod_target, :file_accessors, :non_library_spec, :label, :package, :default_xcconfigs, :resolved_xconfig_by_config
|
32
|
+
|
33
|
+
def initialize(installer, pod_target, non_library_spec = nil, default_xcconfigs = {})
|
34
|
+
@installer = installer
|
35
|
+
@pod_target = pod_target
|
36
|
+
@file_accessors = non_library_spec ? pod_target.file_accessors.select { |fa| fa.spec == non_library_spec } : pod_target.file_accessors.select { |fa| fa.spec.library_specification? }
|
37
|
+
@non_library_spec = non_library_spec
|
38
|
+
@label = (non_library_spec ? pod_target.non_library_spec_label(non_library_spec) : pod_target.label)
|
39
|
+
@package_dir = installer.sandbox.pod_dir(pod_target.pod_name)
|
40
|
+
@package = installer.sandbox.pod_dir(pod_target.pod_name).relative_path_from(installer.config.installation_root).to_s
|
41
|
+
@default_xcconfigs = default_xcconfigs
|
42
|
+
@resolved_xconfig_by_config = {}
|
43
|
+
end
|
44
|
+
|
45
|
+
def bazel_label(relative_to: nil)
|
46
|
+
package_basename = File.basename(package)
|
47
|
+
if package == relative_to
|
48
|
+
":#{label}"
|
49
|
+
elsif package_basename == label
|
50
|
+
"//#{package}"
|
51
|
+
else
|
52
|
+
"//#{package}:#{label}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def build_settings_label(config)
|
57
|
+
relative_sandbox_root = @installer.sandbox.root.relative_path_from(@installer.config.installation_root).to_s
|
58
|
+
cocoapods_bazel_path = File.join(relative_sandbox_root, 'cocoapods-bazel')
|
59
|
+
|
60
|
+
"//#{cocoapods_bazel_path}:#{config}"
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_host
|
64
|
+
unless (app_host_info = pod_target.test_app_hosts_by_spec_name[non_library_spec.name])
|
65
|
+
return
|
66
|
+
end
|
67
|
+
|
68
|
+
app_spec, app_target = *app_host_info
|
69
|
+
Target.new(installer, app_target, app_spec)
|
70
|
+
end
|
71
|
+
|
72
|
+
def type
|
73
|
+
platform = pod_target.platform.name
|
74
|
+
case non_library_spec&.spec_type
|
75
|
+
when nil
|
76
|
+
'apple_framework'
|
77
|
+
when :app
|
78
|
+
"#{platform}_application"
|
79
|
+
when :test
|
80
|
+
"#{platform}_#{non_library_spec.test_type}_test"
|
81
|
+
else
|
82
|
+
raise "Unhandled: #{non_library_spec.spec_type}"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def dependent_targets_by_config
|
87
|
+
targets =
|
88
|
+
case non_library_spec&.spec_type
|
89
|
+
when nil
|
90
|
+
pod_target.dependent_targets_by_config
|
91
|
+
when :app
|
92
|
+
pod_target.app_dependent_targets_by_spec_name_by_config[non_library_spec.name].transform_values { |v| v + [pod_target] }
|
93
|
+
when :test
|
94
|
+
pod_target.test_dependent_targets_by_spec_name_by_config[non_library_spec.name].transform_values { |v| v + [pod_target] }
|
95
|
+
else
|
96
|
+
raise "Unhandled: #{non_library_spec.spec_type}"
|
97
|
+
end
|
98
|
+
|
99
|
+
targets.transform_values { |v| v.uniq.map { |target| self.class.new(installer, target) } }
|
100
|
+
end
|
101
|
+
|
102
|
+
def product_module_name
|
103
|
+
name = resolved_value_by_build_setting('PRODUCT_MODULE_NAME') || resolved_value_by_build_setting('PRODUCT_NAME') ||
|
104
|
+
if non_library_spec
|
105
|
+
label.tr('-', '_')
|
106
|
+
else
|
107
|
+
pod_target.product_module_name
|
108
|
+
end
|
109
|
+
|
110
|
+
raise 'The product module name must be the same for both debug and release.' unless name.is_a? String
|
111
|
+
|
112
|
+
name.gsub(/^([0-9])/, '_\1').gsub(/[^a-zA-Z0-9_]/, '_')
|
113
|
+
end
|
114
|
+
|
115
|
+
def swift_objc_bridging_header
|
116
|
+
resolved_value_by_build_setting('SWIFT_OBJC_BRIDGING_HEADER')
|
117
|
+
end
|
118
|
+
|
119
|
+
def uses_swift?
|
120
|
+
file_accessors.any? { |fa| fa.source_files.any? { |s| s.extname == '.swift' } }
|
121
|
+
end
|
122
|
+
|
123
|
+
def pod_target_xcconfig_by_build_setting
|
124
|
+
debug_xcconfig = resolved_xcconfig(configuration: :debug)
|
125
|
+
release_xcconfig = resolved_xcconfig(configuration: :release)
|
126
|
+
debug_only_xcconfig = debug_xcconfig.reject { |k, v| release_xcconfig[k] == v }
|
127
|
+
release_only_xcconfig = release_xcconfig.reject { |k, v| debug_xcconfig[k] == v }
|
128
|
+
|
129
|
+
xconfig_by_build_setting = {}
|
130
|
+
xconfig_by_build_setting[build_settings_label(:debug)] = debug_only_xcconfig unless debug_only_xcconfig.empty?
|
131
|
+
xconfig_by_build_setting[build_settings_label(:release)] = release_only_xcconfig unless release_only_xcconfig.empty?
|
132
|
+
xconfig_by_build_setting
|
133
|
+
end
|
134
|
+
|
135
|
+
def common_pod_target_xcconfig
|
136
|
+
debug_xcconfig = resolved_xcconfig(configuration: :debug)
|
137
|
+
release_xcconfig = resolved_xcconfig(configuration: :release)
|
138
|
+
common_xcconfig = debug_xcconfig.select { |k, v| release_xcconfig[k] == v }
|
139
|
+
# If the value is an array, merge it into a string.
|
140
|
+
common_xcconfig.map do |k, v|
|
141
|
+
[k, v.is_a?(Array) ? v.shelljoin : v]
|
142
|
+
end.to_h
|
143
|
+
end
|
144
|
+
|
145
|
+
def resolved_xcconfig(configuration:)
|
146
|
+
unless resolved_xconfig_by_config[configuration]
|
147
|
+
xcconfig = pod_target_xcconfig(configuration: configuration)
|
148
|
+
resolved_xconfig_by_config[configuration] = resolve_xcconfig(xcconfig)[1]
|
149
|
+
end
|
150
|
+
resolved_xconfig_by_config[configuration].clone
|
151
|
+
end
|
152
|
+
|
153
|
+
def pod_target_xcconfig(configuration:)
|
154
|
+
pod_target
|
155
|
+
.build_settings_for_spec(non_library_spec || pod_target.root_spec, configuration: configuration)
|
156
|
+
.merged_pod_target_xcconfigs
|
157
|
+
.to_h
|
158
|
+
.merge(
|
159
|
+
'CONFIGURATION' => configuration.to_s.capitalize,
|
160
|
+
'PODS_TARGET_SRCROOT' => ':',
|
161
|
+
'SRCROOT' => ':',
|
162
|
+
'SDKROOT' => '__BAZEL_XCODE_SDKROOT__'
|
163
|
+
)
|
164
|
+
end
|
165
|
+
|
166
|
+
def resolved_value_by_build_setting(setting, additional_settings: {}, is_label_argument: false)
|
167
|
+
debug_settings = pod_target_xcconfig(configuration: :debug).merge(additional_settings)
|
168
|
+
debug_value = resolved_build_setting_value(setting, settings: debug_settings)
|
169
|
+
release_settings = pod_target_xcconfig(configuration: :release).merge(additional_settings)
|
170
|
+
release_value = resolved_build_setting_value(setting, settings: release_settings)
|
171
|
+
if debug_value == release_value
|
172
|
+
debug_value&.empty? && is_label_argument ? nil : debug_value
|
173
|
+
else
|
174
|
+
value_by_build_setting = {
|
175
|
+
build_settings_label(:debug) => debug_value.empty? && is_label_argument ? nil : debug_value,
|
176
|
+
build_settings_label(:release) => release_value.empty? && is_label_argument ? nil : release_value
|
177
|
+
}
|
178
|
+
StarlarkCompiler::AST::FunctionCall.new('select', value_by_build_setting)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def pod_target_xcconfig_header_search_paths(configuration)
|
183
|
+
settings = pod_target_xcconfig(configuration: configuration).merge('PODS_TARGET_SRCROOT' => @package)
|
184
|
+
resolved_build_setting_value('HEADER_SEARCH_PATHS', settings: settings) || []
|
185
|
+
end
|
186
|
+
|
187
|
+
def pod_target_xcconfig_user_header_search_paths(configuration)
|
188
|
+
settings = pod_target_xcconfig(configuration: configuration).merge('PODS_TARGET_SRCROOT' => @package)
|
189
|
+
resolved_build_setting_value('USER_HEADER_SEARCH_PATHS', settings: settings) || []
|
190
|
+
end
|
191
|
+
|
192
|
+
def pod_target_copts(type)
|
193
|
+
setting =
|
194
|
+
case type
|
195
|
+
when :swift then 'OTHER_SWIFT_FLAGS'
|
196
|
+
when :objc then 'OTHER_CFLAGS'
|
197
|
+
else raise "#Unsupported type #{type}"
|
198
|
+
end
|
199
|
+
copts = resolved_value_by_build_setting(setting)
|
200
|
+
copts = [copts] if copts&.is_a?(String)
|
201
|
+
|
202
|
+
debug_copts = copts_for_search_paths_by_config(type, :debug)
|
203
|
+
release_copts = copts_for_search_paths_by_config(type, :release)
|
204
|
+
copts_for_search_paths =
|
205
|
+
if debug_copts.sort == release_copts.sort
|
206
|
+
debug_copts
|
207
|
+
else
|
208
|
+
copts_by_build_setting = {
|
209
|
+
build_settings_label(:debug) => debug_copts,
|
210
|
+
build_settings_label(:release) => release_copts
|
211
|
+
}
|
212
|
+
StarlarkCompiler::AST::FunctionCall.new('select', copts_by_build_setting)
|
213
|
+
end
|
214
|
+
|
215
|
+
if copts
|
216
|
+
if copts.is_a?(Array)
|
217
|
+
if copts_for_search_paths.is_a?(Array)
|
218
|
+
copts + copts_for_search_paths
|
219
|
+
else
|
220
|
+
starlark { copts_for_search_paths + copts }
|
221
|
+
end
|
222
|
+
elsif copts_for_search_paths.is_a?(Array) && copts_for_search_paths.empty?
|
223
|
+
copts
|
224
|
+
else
|
225
|
+
starlark { copts + copts_for_search_paths }
|
226
|
+
end
|
227
|
+
else
|
228
|
+
copts_for_search_paths
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
def copts_for_search_paths_by_config(type, configuration)
|
233
|
+
additional_flag =
|
234
|
+
case type
|
235
|
+
when :swift then '-Xcc'
|
236
|
+
when :objc then nil
|
237
|
+
else raise "#Unsupported type #{type}"
|
238
|
+
end
|
239
|
+
|
240
|
+
copts = []
|
241
|
+
pod_target_xcconfig_header_search_paths(configuration).each do |path|
|
242
|
+
iquote = "-I#{path}"
|
243
|
+
copts << additional_flag if additional_flag
|
244
|
+
copts << iquote
|
245
|
+
end
|
246
|
+
|
247
|
+
pod_target_xcconfig_user_header_search_paths(configuration).each do |path|
|
248
|
+
iquote = "-iquote#{path}"
|
249
|
+
copts << additional_flag if additional_flag
|
250
|
+
copts << iquote
|
251
|
+
end
|
252
|
+
copts
|
253
|
+
end
|
254
|
+
|
255
|
+
def pod_target_infoplists_by_build_setting
|
256
|
+
debug_plist = resolved_build_setting_value('INFOPLIST_FILE', settings: pod_target_xcconfig(configuration: :debug))
|
257
|
+
release_plist = resolved_build_setting_value('INFOPLIST_FILE', settings: pod_target_xcconfig(configuration: :release))
|
258
|
+
if debug_plist == release_plist
|
259
|
+
[]
|
260
|
+
else
|
261
|
+
plist_by_build_setting = {}
|
262
|
+
plist_by_build_setting[build_settings_label(:debug)] = [debug_plist] if debug_plist
|
263
|
+
plist_by_build_setting[build_settings_label(:release)] = [release_plist] if release_plist
|
264
|
+
plist_by_build_setting
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
def common_pod_target_infoplists(additional_plist: nil)
|
269
|
+
debug_plist = resolved_build_setting_value('INFOPLIST_FILE', settings: pod_target_xcconfig(configuration: :debug))
|
270
|
+
release_plist = resolved_build_setting_value('INFOPLIST_FILE', settings: pod_target_xcconfig(configuration: :release))
|
271
|
+
if debug_plist == release_plist
|
272
|
+
[debug_plist, additional_plist].compact
|
273
|
+
else
|
274
|
+
[additional_plist].compact
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
def to_rule_kwargs
|
279
|
+
kwargs = RuleArgs.new do |args|
|
280
|
+
args
|
281
|
+
.add(:name, label)
|
282
|
+
.add(:module_name, product_module_name, defaults: [label])
|
283
|
+
.add(:module_map, !non_library_spec && file_accessors.map(&:module_map).find(&:itself)&.relative_path_from(@package_dir)&.to_s, defaults: [nil, false]).
|
284
|
+
|
285
|
+
# public headers
|
286
|
+
add(:public_headers, glob(attr: :public_headers, sorted: false).yield_self { |f| case f when Array then f.reject { |path| path.include? '.framework/' } else f end }, defaults: [[]])
|
287
|
+
.add(:private_headers, glob(attr: :private_headers).yield_self { |f| case f when Array then f.reject { |path| path.include? '.framework/' } else f end }, defaults: [[]])
|
288
|
+
.add(:pch, glob(attr: :prefix_header, return_files: true).first, defaults: [nil])
|
289
|
+
.add(:data, glob(attr: :resources, exclude_directories: 0), defaults: [[]])
|
290
|
+
.add(:resource_bundles, {}, defaults: [{}])
|
291
|
+
.add(:swift_version, uses_swift? && pod_target.swift_version, defaults: [nil, false])
|
292
|
+
.add(:swift_objc_bridging_header, swift_objc_bridging_header, defaults: [nil])
|
293
|
+
|
294
|
+
# xcconfigs
|
295
|
+
resolve_xcconfig(common_pod_target_xcconfig, default_xcconfigs: default_xcconfigs).tap do |name, xcconfig|
|
296
|
+
args
|
297
|
+
.add(:default_xcconfig_name, name, defaults: [nil])
|
298
|
+
.add(:xcconfig, xcconfig, defaults: [{}])
|
299
|
+
end
|
300
|
+
# xcconfig_by_build_setting
|
301
|
+
args.add(:xcconfig_by_build_setting, pod_target_xcconfig_by_build_setting, defaults: [{}])
|
302
|
+
end.kwargs
|
303
|
+
|
304
|
+
file_accessors.group_by { |fa| fa.spec_consumer.requires_arc.class }.tap do |fa_by_arc|
|
305
|
+
srcs = Hash.new { |h, k| h[k] = [] }
|
306
|
+
non_arc_srcs = Hash.new { |h, k| h[k] = [] }
|
307
|
+
expand = ->(g) { expand_glob(g, extensions: %w[h hh m mm swift c cc cpp]) }
|
308
|
+
|
309
|
+
Array(fa_by_arc[TrueClass]).each do |fa|
|
310
|
+
srcs[fa.spec_consumer.exclude_files] += fa.spec_consumer.source_files.flat_map(&expand)
|
311
|
+
end
|
312
|
+
Array(fa_by_arc[FalseClass]).each do |fa|
|
313
|
+
non_arc_srcs[fa.spec_consumer.exclude_files] += fa.spec_consumer.source_files.flat_map(&expand)
|
314
|
+
end
|
315
|
+
(Array(fa_by_arc[Array]) + Array(fa_by_arc[String])).each do |fa|
|
316
|
+
arc_globs = Array(fa.spec_consumer.requires_arc).flat_map(&expand)
|
317
|
+
globs = fa.spec_consumer.source_files.flat_map(&expand)
|
318
|
+
|
319
|
+
srcs[fa.spec_consumer.exclude_files] += arc_globs
|
320
|
+
non_arc_srcs[fa.spec_consumer.exclude_files + arc_globs] += globs
|
321
|
+
end
|
322
|
+
|
323
|
+
m = lambda do |h|
|
324
|
+
h.delete_if do |_, v|
|
325
|
+
v.delete_if { |g| g.include?('.framework/') }
|
326
|
+
v.empty?
|
327
|
+
end
|
328
|
+
return [] if h.empty?
|
329
|
+
|
330
|
+
h.map do |excludes, globs|
|
331
|
+
excludes = excludes.empty? ? {} : { exclude: excludes.flat_map(&method(:expand_glob)) }
|
332
|
+
starlark { function_call(:glob, globs.uniq, **excludes) }
|
333
|
+
end.reduce(&:+)
|
334
|
+
end
|
335
|
+
|
336
|
+
kwargs[:srcs] = m[srcs]
|
337
|
+
kwargs[:non_arc_srcs] = m[non_arc_srcs]
|
338
|
+
end
|
339
|
+
|
340
|
+
file_accessors.each_with_object({}) do |fa, bundles|
|
341
|
+
fa.spec_consumer.resource_bundles.each do |name, file_patterns|
|
342
|
+
bundle = bundles[name] ||= {}
|
343
|
+
patterns_by_exclude = bundle[fa.spec_consumer.exclude_files] ||= []
|
344
|
+
patterns_by_exclude.concat(file_patterns.flat_map { |g| expand_glob(g, expand_directories: true) })
|
345
|
+
end
|
346
|
+
end.tap do |bundles|
|
347
|
+
kwargs[:resource_bundles] = bundles.map do |bundle_name, patterns_by_excludes|
|
348
|
+
patterns_by_excludes.delete_if { |_, v| v.empty? }
|
349
|
+
# resources implicitly have dirs expanded by CocoaPods
|
350
|
+
resources = patterns_by_excludes.map do |excludes, globs|
|
351
|
+
excludes = excludes.empty? ? {} : { exclude: excludes.flat_map(&method(:expand_glob)) }
|
352
|
+
starlark { function_call(:glob, globs.uniq, exclude_directories: 0, **excludes) }
|
353
|
+
end.reduce(&:+)
|
354
|
+
[bundle_name, resources]
|
355
|
+
end.to_h
|
356
|
+
end
|
357
|
+
|
358
|
+
# non-propagated stuff for a target that should build.
|
359
|
+
if pod_target.should_build?
|
360
|
+
kwargs[:swift_copts] = pod_target_copts(:swift)
|
361
|
+
kwargs[:objc_copts] = pod_target_copts(:objc)
|
362
|
+
linkopts = resolved_value_by_build_setting('OTHER_LDFLAGS')
|
363
|
+
linkopts = [linkopts] if linkopts.is_a? String
|
364
|
+
kwargs[:linkopts] = linkopts || []
|
365
|
+
end
|
366
|
+
|
367
|
+
# propagated
|
368
|
+
kwargs[:defines] = []
|
369
|
+
kwargs[:other_inputs] = []
|
370
|
+
kwargs[:linking_style] = nil
|
371
|
+
kwargs[:runtime_deps] = []
|
372
|
+
kwargs[:sdk_dylibs] = file_accessors.flat_map { |fa| fa.spec_consumer.libraries }.sort.uniq
|
373
|
+
kwargs[:sdk_frameworks] = file_accessors.flat_map { |fa| fa.spec_consumer.frameworks }.sort.uniq
|
374
|
+
kwargs[:sdk_includes] = []
|
375
|
+
kwargs[:weak_sdk_frameworks] = file_accessors.flat_map { |fa| fa.spec_consumer.weak_frameworks }.sort.uniq
|
376
|
+
|
377
|
+
kwargs[:vendored_static_frameworks] = glob(attr: :vendored_static_frameworks, return_files: true)
|
378
|
+
kwargs[:vendored_dynamic_frameworks] = glob(attr: :vendored_dynamic_frameworks, return_files: true)
|
379
|
+
kwargs[:vendored_static_libraries] = glob(attr: :vendored_static_libraries, return_files: true)
|
380
|
+
kwargs[:vendored_dynamic_libraries] = glob(attr: :vendored_dynamic_libraries, return_files: true)
|
381
|
+
kwargs[:vendored_xcframeworks] = vendored_xcframeworks
|
382
|
+
|
383
|
+
# any compatible provider: CCProvider, SwiftInfo, etc
|
384
|
+
kwargs[:deps] = deps_by_config
|
385
|
+
|
386
|
+
case non_library_spec&.spec_type
|
387
|
+
when :test
|
388
|
+
kwargs.merge!(test_kwargs)
|
389
|
+
when :app
|
390
|
+
kwargs.merge!(app_kwargs)
|
391
|
+
when nil
|
392
|
+
kwargs.merge!(framework_kwargs)
|
393
|
+
end
|
394
|
+
|
395
|
+
defaults = self.defaults
|
396
|
+
kwargs.delete_if { |k, v| defaults[k] == v }
|
397
|
+
kwargs
|
398
|
+
end
|
399
|
+
|
400
|
+
def defaults
|
401
|
+
{
|
402
|
+
module_name: label,
|
403
|
+
module_map: nil,
|
404
|
+
srcs: [],
|
405
|
+
non_arc_srcs: [],
|
406
|
+
hdrs: [],
|
407
|
+
pch: nil,
|
408
|
+
data: [],
|
409
|
+
resource_bundles: {},
|
410
|
+
|
411
|
+
swift_copts: [],
|
412
|
+
objc_copts: [],
|
413
|
+
cc_copts: [],
|
414
|
+
defines: [],
|
415
|
+
linkopts: [],
|
416
|
+
other_inputs: [],
|
417
|
+
linking_style: nil,
|
418
|
+
runtime_deps: [],
|
419
|
+
sdk_dylibs: [],
|
420
|
+
sdk_frameworks: [],
|
421
|
+
sdk_includes: [],
|
422
|
+
weak_sdk_frameworks: [],
|
423
|
+
|
424
|
+
bundle_id: nil,
|
425
|
+
env: {},
|
426
|
+
infoplists_by_build_setting: [],
|
427
|
+
infoplists: [],
|
428
|
+
minimum_os_version: nil,
|
429
|
+
test_host: nil,
|
430
|
+
platforms: {},
|
431
|
+
|
432
|
+
app_icons: [],
|
433
|
+
bundle_name: nil,
|
434
|
+
entitlements: nil,
|
435
|
+
entitlements_validation: nil,
|
436
|
+
extensions: [],
|
437
|
+
frameworks: [],
|
438
|
+
ipa_post_processor: nil,
|
439
|
+
launch_images: [],
|
440
|
+
launch_storyboard: nil,
|
441
|
+
provisioning_profile: nil,
|
442
|
+
resources: [],
|
443
|
+
settings_bundle: [],
|
444
|
+
strings: [],
|
445
|
+
version: [],
|
446
|
+
watch_application: [],
|
447
|
+
|
448
|
+
vendored_static_frameworks: [],
|
449
|
+
vendored_dynamic_frameworks: [],
|
450
|
+
vendored_static_libraries: [],
|
451
|
+
vendored_dynamic_libraries: [],
|
452
|
+
vendored_xcframeworks: [],
|
453
|
+
|
454
|
+
deps: []
|
455
|
+
}
|
456
|
+
end
|
457
|
+
|
458
|
+
def deps_by_config
|
459
|
+
debug_targets = dependent_targets_by_config[:debug]
|
460
|
+
release_targets = dependent_targets_by_config[:release]
|
461
|
+
|
462
|
+
debug_labels = debug_targets.map { |dt| dt.bazel_label(relative_to: package) }
|
463
|
+
release_labels = release_targets.map { |dt| dt.bazel_label(relative_to: package) }
|
464
|
+
shared_labels = (debug_labels & release_labels).uniq
|
465
|
+
|
466
|
+
debug_only_labels = debug_labels - shared_labels
|
467
|
+
release_only_labels = release_labels - shared_labels
|
468
|
+
|
469
|
+
sorted_debug_labels = Pod::Bazel::Util.sort_labels(debug_only_labels)
|
470
|
+
sorted_release_labels = Pod::Bazel::Util.sort_labels(release_only_labels)
|
471
|
+
sorted_shared_labels = Pod::Bazel::Util.sort_labels(shared_labels)
|
472
|
+
|
473
|
+
labels_by_config = {}
|
474
|
+
|
475
|
+
if !sorted_debug_labels.empty? || !sorted_release_labels.empty?
|
476
|
+
labels_by_config[build_settings_label(:debug)] = sorted_debug_labels
|
477
|
+
labels_by_config[build_settings_label(:release)] = sorted_release_labels
|
478
|
+
end
|
479
|
+
|
480
|
+
if labels_by_config.empty? # no per-config dependency
|
481
|
+
sorted_shared_labels
|
482
|
+
elsif sorted_shared_labels.empty? # per-config dependencies exist, avoiding adding an empty array
|
483
|
+
StarlarkCompiler::AST::FunctionCall.new('select', labels_by_config)
|
484
|
+
else # both per-config and shared dependencies exist
|
485
|
+
starlark { StarlarkCompiler::AST::FunctionCall.new('select', labels_by_config) + sorted_shared_labels }
|
486
|
+
end
|
487
|
+
end
|
488
|
+
|
489
|
+
def glob(attr:, return_files: !pod_target.sandbox.local?(pod_target.pod_name), sorted: true, excludes: [], exclude_directories: 1)
|
490
|
+
if !return_files
|
491
|
+
case attr
|
492
|
+
when :public_headers then attr = :public_header_files
|
493
|
+
when :private_headers then attr = :private_header_files
|
494
|
+
end
|
495
|
+
|
496
|
+
globs = file_accessors.map(&:spec_consumer).flat_map(&attr).flat_map { |g| expand_glob(g, expand_directories: exclude_directories != 1) }
|
497
|
+
excludes += file_accessors.map(&:spec_consumer).flat_map(&:exclude_files).flat_map { |g| expand_glob(g) }
|
498
|
+
excludes = excludes.empty? ? {} : { exclude: excludes }
|
499
|
+
excludes[:exclude_directories] = exclude_directories unless exclude_directories == 1
|
500
|
+
if globs.empty?
|
501
|
+
[]
|
502
|
+
else
|
503
|
+
starlark { function_call(:glob, globs, **excludes) }
|
504
|
+
end
|
505
|
+
else
|
506
|
+
file_accessors.flat_map(&attr)
|
507
|
+
.compact
|
508
|
+
.map { |path| path.relative_path_from(@package_dir).to_s }
|
509
|
+
.yield_self { |paths| sorted ? paths.sort : paths }
|
510
|
+
.uniq
|
511
|
+
end
|
512
|
+
end
|
513
|
+
|
514
|
+
def expand_glob(glob, extensions: nil, expand_directories: false)
|
515
|
+
if (m = glob.match(/\{([^\{\}]+)\}/))
|
516
|
+
m[1].split(',').flat_map do |alt|
|
517
|
+
expand_glob("#{m.pre_match}#{alt}#{m.post_match}")
|
518
|
+
end.uniq
|
519
|
+
elsif (m = glob.match(/\[([^\[\]]+)\]/))
|
520
|
+
m[1].each_char.flat_map do |alt|
|
521
|
+
expand_glob("#{m.pre_match}#{alt}#{m.post_match}")
|
522
|
+
end.uniq
|
523
|
+
elsif extensions && File.extname(glob).empty?
|
524
|
+
glob = glob.chomp('**/*') # If we reach here and the glob ends with **/*, we need to avoid duplicating it (we do not want to end up with **/*/**/*)
|
525
|
+
if File.basename(glob) == '*'
|
526
|
+
extensions.map { |ext| "#{glob}.#{ext}" }
|
527
|
+
else
|
528
|
+
extensions.map do |ext|
|
529
|
+
File.join(glob, '**', "*.#{ext}")
|
530
|
+
end
|
531
|
+
end
|
532
|
+
elsif expand_directories
|
533
|
+
if glob.end_with?('/**/*')
|
534
|
+
[glob]
|
535
|
+
elsif glob.end_with?('/*')
|
536
|
+
[glob.sub(%r{/\*$}, '/**/*')]
|
537
|
+
else
|
538
|
+
[glob, glob.chomp('/') + '/**/*']
|
539
|
+
end
|
540
|
+
else
|
541
|
+
[glob]
|
542
|
+
end
|
543
|
+
end
|
544
|
+
|
545
|
+
def framework_kwargs
|
546
|
+
{
|
547
|
+
visibility: ['//visibility:public'],
|
548
|
+
platforms: { pod_target.platform.string_name.downcase => pod_target.platform.deployment_target.to_s }
|
549
|
+
}
|
550
|
+
end
|
551
|
+
|
552
|
+
def test_kwargs
|
553
|
+
{
|
554
|
+
bundle_id: resolved_value_by_build_setting('PRODUCT_BUNDLE_IDENTIFIER'),
|
555
|
+
env: pod_target.scheme_for_spec(non_library_spec).fetch(:environment_variables, {}),
|
556
|
+
infoplists_by_build_setting: pod_target_infoplists_by_build_setting,
|
557
|
+
infoplists: common_pod_target_infoplists(additional_plist: nil_if_empty(non_library_spec.consumer(pod_target.platform).info_plist)),
|
558
|
+
minimum_os_version: pod_target.deployment_target_for_non_library_spec(non_library_spec),
|
559
|
+
test_host: test_host&.bazel_label(relative_to: package) || file_accessors.any? { |fa| fa.spec_consumer.requires_app_host? } || nil
|
560
|
+
}
|
561
|
+
end
|
562
|
+
|
563
|
+
def app_kwargs
|
564
|
+
# maps to kwargs listed for https://github.com/bazelbuild/rules_apple/blob/master/doc/rules-ios.md#ios_application
|
565
|
+
{
|
566
|
+
app_icons: [],
|
567
|
+
bundle_id: resolved_value_by_build_setting('PRODUCT_BUNDLE_IDENTIFIER') || "org.cocoapods.#{label}",
|
568
|
+
bundle_name: nil,
|
569
|
+
entitlements: resolved_value_by_build_setting('CODE_SIGN_ENTITLEMENTS', is_label_argument: true),
|
570
|
+
entitlements_validation: nil,
|
571
|
+
extensions: [],
|
572
|
+
families: app_targeted_device_families,
|
573
|
+
frameworks: [],
|
574
|
+
infoplists_by_build_setting: pod_target_infoplists_by_build_setting,
|
575
|
+
infoplists: common_pod_target_infoplists(additional_plist: nil_if_empty(non_library_spec.consumer(pod_target.platform).info_plist)),
|
576
|
+
ipa_post_processor: nil,
|
577
|
+
launch_images: [],
|
578
|
+
launch_storyboard: nil,
|
579
|
+
minimum_os_version: pod_target.deployment_target_for_non_library_spec(non_library_spec),
|
580
|
+
provisioning_profile: nil,
|
581
|
+
resources: [],
|
582
|
+
settings_bundle: [],
|
583
|
+
strings: [],
|
584
|
+
version: [],
|
585
|
+
watch_application: []
|
586
|
+
}
|
587
|
+
end
|
588
|
+
|
589
|
+
def app_targeted_device_families
|
590
|
+
# Reads the targeted device families from xconfig TARGETED_DEVICE_FAMILY. Supports both iphone and ipad by default.
|
591
|
+
device_families = resolved_value_by_build_setting('TARGETED_DEVICE_FAMILY') || '1,2'
|
592
|
+
raise 'TARGETED_DEVICE_FAMILY must be the same for both debug and release.' unless device_families.is_a? String
|
593
|
+
|
594
|
+
device_families.split(',').map do |device_family|
|
595
|
+
case device_family
|
596
|
+
when '1' then 'iphone'
|
597
|
+
when '2' then 'ipad'
|
598
|
+
else raise "Unsupported device family: #{device_family}"
|
599
|
+
end
|
600
|
+
end
|
601
|
+
end
|
602
|
+
|
603
|
+
def vendored_xcframeworks
|
604
|
+
pod_target.xcframeworks.values.flatten(1).uniq.map do |xcframework|
|
605
|
+
{
|
606
|
+
'name' => xcframework.name,
|
607
|
+
'slices' => xcframework.slices.map do |slice|
|
608
|
+
{
|
609
|
+
'identifier' => slice.identifier,
|
610
|
+
'platform' => slice.platform.name.to_s,
|
611
|
+
'platform_variant' => slice.platform_variant.to_s,
|
612
|
+
'supported_archs' => slice.supported_archs,
|
613
|
+
'path' => slice.path.relative_path_from(@package_dir).to_s,
|
614
|
+
'build_type' => { 'linkage' => slice.build_type.linkage.to_s, 'packaging' => slice.build_type.packaging.to_s }
|
615
|
+
}
|
616
|
+
end
|
617
|
+
}
|
618
|
+
end
|
619
|
+
end
|
620
|
+
|
621
|
+
def nil_if_empty(arr)
|
622
|
+
arr.empty? ? nil : arr
|
623
|
+
end
|
624
|
+
|
625
|
+
def starlark(&blk)
|
626
|
+
StarlarkCompiler::AST.build(&blk)
|
627
|
+
end
|
628
|
+
end
|
629
|
+
end
|
630
|
+
end
|