cocoapods-bazel 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
![](https://github.com/ob/cocoapods-bazel/workflows/master/badge.svg)
|
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
|