cocoapods-bin 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/Gemfile +13 -0
  4. data/Gemfile.lock +100 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +15 -0
  7. data/Rakefile +13 -0
  8. data/cocoapods-bin.gemspec +26 -0
  9. data/lib/cocoapods-bin/command/bin/init.rb +66 -0
  10. data/lib/cocoapods-bin/command/bin/lib/lint.rb +94 -0
  11. data/lib/cocoapods-bin/command/bin/lib.rb +12 -0
  12. data/lib/cocoapods-bin/command/bin/open.rb +60 -0
  13. data/lib/cocoapods-bin/command/bin/repo/push.rb +98 -0
  14. data/lib/cocoapods-bin/command/bin/repo.rb +12 -0
  15. data/lib/cocoapods-bin/command/bin/spec/create.rb +68 -0
  16. data/lib/cocoapods-bin/command/bin/spec/lint.rb +52 -0
  17. data/lib/cocoapods-bin/command/bin/spec.rb +13 -0
  18. data/lib/cocoapods-bin/command/bin.rb +52 -0
  19. data/lib/cocoapods-bin/command.rb +1 -0
  20. data/lib/cocoapods-bin/config/config.rb +52 -0
  21. data/lib/cocoapods-bin/config/config_asker.rb +50 -0
  22. data/lib/cocoapods-bin/gem_version.rb +9 -0
  23. data/lib/cocoapods-bin/helpers/sources_helper.rb +31 -0
  24. data/lib/cocoapods-bin/helpers/spec_files_helper.rb +17 -0
  25. data/lib/cocoapods-bin/helpers/spec_generator.rb +86 -0
  26. data/lib/cocoapods-bin/helpers.rb +3 -0
  27. data/lib/cocoapods-bin/native/analyzer.rb +28 -0
  28. data/lib/cocoapods-bin/native/installation_options.rb +24 -0
  29. data/lib/cocoapods-bin/native/installer.rb +73 -0
  30. data/lib/cocoapods-bin/native/linter.rb +29 -0
  31. data/lib/cocoapods-bin/native/pod_source_installer.rb +15 -0
  32. data/lib/cocoapods-bin/native/podfile.rb +67 -0
  33. data/lib/cocoapods-bin/native/resolver.rb +103 -0
  34. data/lib/cocoapods-bin/native/source.rb +35 -0
  35. data/lib/cocoapods-bin/native/source_provider_hook.rb +11 -0
  36. data/lib/cocoapods-bin/native/sources_manager.rb +18 -0
  37. data/lib/cocoapods-bin/native/validator.rb +16 -0
  38. data/lib/cocoapods-bin/native.rb +13 -0
  39. data/lib/cocoapods-bin.rb +1 -0
  40. data/lib/cocoapods_plugin.rb +3 -0
  41. data/spec/command/bin_spec.rb +12 -0
  42. data/spec/spec_helper.rb +50 -0
  43. metadata +143 -0
@@ -0,0 +1,13 @@
1
+ require 'cocoapods-bin/command/bin/spec/create'
2
+ require 'cocoapods-bin/command/bin/spec/lint'
3
+
4
+ module Pod
5
+ class Command
6
+ class Bin < Command
7
+ class Spec < Bin
8
+ self.abstract_command = true
9
+ self.summary = '管理二进制 spec.'
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,52 @@
1
+ require 'cocoapods-bin/command/bin/init'
2
+ require 'cocoapods-bin/command/bin/spec'
3
+ require 'cocoapods-bin/command/bin/lib'
4
+ require 'cocoapods-bin/command/bin/repo'
5
+ require 'cocoapods-bin/command/bin/open'
6
+ require 'cocoapods-bin/helpers'
7
+
8
+ module Pod
9
+ class Command
10
+ # This is an example of a cocoapods plugin adding a top-level subcommand
11
+ # to the 'pod' command.
12
+ #
13
+ # You can also create subcommands of existing or new commands. Say you
14
+ # wanted to add a subcommand to `list` to show newly deprecated pods,
15
+ # (e.g. `pod list deprecated`), there are a few things that would need
16
+ # to change.
17
+ #
18
+ # - move this file to `lib/pod/command/list/deprecated.rb` and update
19
+ # the class to exist in the the Pod::Command::List namespace
20
+ # - change this class to extend from `List` instead of `Command`. This
21
+ # tells the plugin system that it is a subcommand of `list`.
22
+ # - edit `lib/cocoapods_plugins.rb` to require this file
23
+ #
24
+ # @todo Create a PR to add your plugin to CocoaPods/cocoapods.org
25
+ # in the `plugins.json` file, once your plugin is released.
26
+ #
27
+ class Bin < Command
28
+ include CBin::SourcesHelper
29
+ include CBin::SpecFilesHelper
30
+
31
+ self.abstract_command = true
32
+
33
+ self.default_subcommand = 'open'
34
+ self.summary = '组件二进制化插件.'
35
+ self.description = <<-DESC
36
+ 组件二进制化插件。利用源码私有源与二进制私有源实现对组件依赖类型的切换。
37
+ DESC
38
+
39
+ def initialize(argv)
40
+ @help = argv.flag?('help')
41
+ super
42
+ end
43
+
44
+ def validate!
45
+ super
46
+ # 这里由于 --help 是在 validate! 方法中提取的,会导致 --help 失效
47
+ # pod lib create 也有这个问题
48
+ banner! if @help
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1 @@
1
+ require 'cocoapods-bin/command/bin'
@@ -0,0 +1,52 @@
1
+ require 'yaml'
2
+
3
+ module CBin
4
+ class Config
5
+ def config_file
6
+ File.expand_path("#{Pod::Config.instance.home_dir}/bin.yml")
7
+ end
8
+
9
+ def template_hash
10
+ {
11
+ 'code_repo_url' => '源码私有源 Git 地址,如> git@git.2dfire.net:ios/cocoapods-spec.git',
12
+ 'binary_repo_url' => '二进制私有源 Git 地址,如> git@git.2dfire.net:ios/cocoapods-spec-binary.git',
13
+ 'binary_download_url' => '二进制下载地址,内部会依次传入组件名称与版本,替换字符串中的 %s ,如> http://iosframeworkserver-shopkeeperclient.app.2dfire.com/download/%s/%s.zip'
14
+ }
15
+ end
16
+
17
+ def sync_config(config)
18
+ File.open(config_file, 'w+') do |f|
19
+ f.write(config.to_yaml)
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def load_config
26
+ if File.exists?(config_file)
27
+ YAML.load_file(config_file)
28
+ else
29
+ Hash[template_hash.map { |k, v| [k, v.split('>', 2).last.strip] }]
30
+ end
31
+ end
32
+
33
+ def respond_to_missing?(method, include_private = false)
34
+ @config.respond_to?(method) || super
35
+ end
36
+
37
+ def method_missing(method, *args, &block)
38
+ @config ||= OpenStruct.new load_config
39
+ if @config.respond_to?(method)
40
+ @config.send(method, *args)
41
+ elsif template_hash.keys.include?(method.to_s)
42
+ raise Pod::Informative, "#{method} 字段必须在配置文件 #{config_file} 中设置, 请执行 init 命令配置或手动修改配置文件".red
43
+ else
44
+ super
45
+ end
46
+ end
47
+ end
48
+
49
+ def self.config
50
+ @config ||= Config.new
51
+ end
52
+ end
@@ -0,0 +1,50 @@
1
+ require 'yaml'
2
+ require 'cocoapods-bin/config/config'
3
+
4
+ module CBin
5
+ class Config
6
+ class Asker
7
+ def show_prompt
8
+ print ' > '.green
9
+ end
10
+
11
+ def ask_with_answer(question, pre_answer)
12
+ print "\n#{question}\n"
13
+
14
+ print "旧值:#{pre_answer}\n" unless pre_answer.nil?
15
+
16
+ answer = ''
17
+ loop do
18
+ show_prompt
19
+ answer = STDIN.gets.chomp
20
+
21
+ if answer == '' && !pre_answer.nil?
22
+ answer = pre_answer
23
+ print answer.yellow
24
+ print "\n"
25
+ end
26
+
27
+ break unless answer.empty?
28
+ end
29
+
30
+ answer
31
+ end
32
+
33
+
34
+ def wellcome_message
35
+ print <<-EOF
36
+
37
+ 开始设置二进制化初始信息.
38
+ 所有的信息都会保存在 #{CBin.config.config_file} 文件中.
39
+ 你可以在对应目录下手动添加编辑该文件. 文件包含的配置信息如下:
40
+
41
+ #{CBin.config.template_hash.to_yaml}
42
+ EOF
43
+ end
44
+
45
+ def done_message
46
+ print "\n设置完成.\n".green
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,9 @@
1
+ module CBin
2
+ VERSION = "0.0.1"
3
+ end
4
+
5
+ module Pod
6
+ def self.match_version?(*version)
7
+ Gem::Dependency.new("", *version).match?('', Pod::VERSION)
8
+ end
9
+ end
@@ -0,0 +1,31 @@
1
+ require 'cocoapods-bin/native'
2
+
3
+ module CBin
4
+ module SourcesHelper
5
+ def sources_manager
6
+ Pod::Config.instance.sources_manager
7
+ end
8
+
9
+ def binary_source
10
+ sources_manager.binary_source
11
+ end
12
+
13
+ def code_source
14
+ sources_manager.code_source
15
+ end
16
+
17
+ # 优先采用对应依赖的 source
18
+ # cocoapods 内部会先匹配前面符合的 specification
19
+ # 只允许二进制的 specification subspec 比源码的 specification subspec 多
20
+ #
21
+ def valid_sources(code_dependencies = false)
22
+ sources = [binary_source, code_source]
23
+ sources.reverse! if code_dependencies
24
+ sources
25
+ end
26
+
27
+ def sources_option(code_dependencies, additional_sources)
28
+ (valid_sources(code_dependencies).map(&:name) + additional_sources).join(',')
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,17 @@
1
+ require 'cocoapods-bin/native'
2
+
3
+ module CBin
4
+ module SpecFilesHelper
5
+ def spec_files
6
+ @spec_files ||= Pathname.glob('*.podspec{,.json}')
7
+ end
8
+
9
+ def binary_spec_files
10
+ @binary_spec_files ||= Pathname.glob('*.binary.podspec{,.json}')
11
+ end
12
+
13
+ def code_spec_files
14
+ @code_spec_files ||= spec_files - binary_spec_files
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,86 @@
1
+ require 'cocoapods'
2
+ require 'cocoapods-bin/config/config'
3
+
4
+ module CBin
5
+ class SpecGenerator
6
+ attr_reader :ref_spec
7
+ attr_reader :spec
8
+
9
+ def initialize(ref_spec, platforms = 'ios')
10
+ @ref_spec = ref_spec
11
+ @platforms = Array(platforms)
12
+ validate!
13
+ end
14
+
15
+ def validate!
16
+ raise StandardError, '不支持自动生成存在 subspec 的二进制 podspec .' if ref_spec.subspecs.any?
17
+ end
18
+
19
+ def generate
20
+ @spec = @ref_spec.dup
21
+ # vendored_frameworks | resources | source | source_files | public_header_files
22
+ # license | resource_bundles
23
+
24
+ # Project Linkin
25
+ @spec.vendored_frameworks = "#{ref_spec.root.name}.framework"
26
+
27
+ # Resources
28
+ extnames = []
29
+ extnames << '*.bundle' if ref_spec_consumer.resource_bundles.any?
30
+ extnames += ref_spec_consumer.resources.map { |r| File.basename(r) } if ref_spec_consumer.resources.any?
31
+ @spec.resources = framework_contents('Resources').flat_map { |r| extnames.map { |e| "#{r}/#{e}" } } if extnames.any?
32
+
33
+ # Source Location
34
+ @spec.source = { http: CBin.config.binary_download_url % [ref_spec.root.name, ref_spec.version] }
35
+
36
+ # Source Code
37
+ @spec.source_files = framework_contents('Headers/*')
38
+ @spec.public_header_files = framework_contents('Headers/*')
39
+
40
+ # Unused for binary
41
+ spec_hash = @spec.to_hash
42
+ # spec_hash.delete('license')
43
+ spec_hash.delete('resource_bundles')
44
+
45
+ # Filter platforms
46
+ platforms = spec_hash['platforms']
47
+ selected_platforms = platforms.select { |k, v| @platforms.include?(k) }
48
+ spec_hash['platforms'] = selected_platforms.empty? ? platforms : selected_platforms
49
+
50
+ @spec = Pod::Specification.from_hash(spec_hash)
51
+
52
+ Pod::UI.message "生成二进制 podspec 内容: "
53
+ @spec.to_pretty_json.split("\n").each do |text|
54
+ Pod::UI.message text
55
+ end
56
+
57
+ @spec
58
+ end
59
+
60
+ def write_to_spec_file(file = filename)
61
+ File.open(file, 'w+') do |f|
62
+ f.write(spec.to_pretty_json)
63
+ end
64
+
65
+ @filename = file
66
+ end
67
+
68
+ def clear_spec_file
69
+ File.delete(@filename) if File.exist?(@filename)
70
+ end
71
+
72
+ def filename
73
+ @filename ||= "#{spec.name}.binary.podspec.json"
74
+ end
75
+
76
+ private
77
+
78
+ def ref_spec_consumer(platform = :ios)
79
+ ref_spec.consumer(:ios)
80
+ end
81
+
82
+ def framework_contents(name)
83
+ ["#{ref_spec.root.name}.framework", "#{ref_spec.root.name}.framework/Versions/A"].map { |path| "#{path}/#{name}" }
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,3 @@
1
+ require 'cocoapods-bin/helpers/sources_helper'
2
+ require 'cocoapods-bin/helpers/spec_generator'
3
+ require 'cocoapods-bin/helpers/spec_files_helper'
@@ -0,0 +1,28 @@
1
+ require 'parallel'
2
+ require 'cocoapods'
3
+
4
+ module Pod
5
+ class Installer
6
+ class Analyzer
7
+ # > 1.5.3 版本
8
+ # rewrite update_repositories
9
+ #
10
+ alias_method :old_update_repositories, :update_repositories
11
+ def update_repositories
12
+ if installation_options.update_source_with_multi_processes
13
+ # 并发更新私有源
14
+ Parallel.each(sources, in_threads: 4) do |source|
15
+ if source.git?
16
+ config.sources_manager.update(source.name, true)
17
+ else
18
+ UI.message "Skipping `#{source.name}` update because the repository is not a git source repository."
19
+ end
20
+ end
21
+ @specs_updated = true
22
+ else
23
+ old_update_repositories
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,24 @@
1
+ require 'cocoapods'
2
+
3
+ module Pod
4
+ class Installer
5
+ class InstallationOptions
6
+ def self.env_option(key, default = true)
7
+ option key, ENV[key.to_s].nil? ? default : ENV[key.to_s] == 'true'
8
+ end
9
+
10
+ # 不同 source 存在相同 spec 名时,默认不警告
11
+ defaults.delete('warn_for_multiple_pod_sources')
12
+ env_option :warn_for_multiple_pod_sources, false
13
+
14
+ # 是否警告不安全 source (如 http )
15
+ env_option :warn_for_unsecure_source, false
16
+
17
+ # 是否多进程执行 install_pod_sources
18
+ env_option :install_with_multi_processes, true
19
+
20
+ # 是否多进程执行 update_repositories
21
+ env_option :update_source_with_multi_processes, true
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,73 @@
1
+ require 'parallel'
2
+ require 'cocoapods'
3
+ require 'cocoapods-bin/native/pod_source_installer'
4
+
5
+ module Pod
6
+ class Installer
7
+ alias_method :old_create_pod_installer, :create_pod_installer
8
+ def create_pod_installer(pod_name)
9
+ installer = old_create_pod_installer(pod_name)
10
+ installer.installation_options = installation_options
11
+ installer
12
+ end
13
+
14
+ # rewrite install_pod_sources
15
+ alias_method :old_install_pod_sources, :install_pod_sources
16
+ def install_pod_sources
17
+ if installation_options.install_with_multi_processes
18
+ @installed_specs = []
19
+ pods_to_install = sandbox_state.added | sandbox_state.changed
20
+ title_options = { :verbose_prefix => '-> '.green }
21
+ # 多进程下载,多线程时 log 会显著交叉,多进程好点,但是多进程需要利用文件锁对 cache 进行保护
22
+ # in_processes: 10
23
+ Parallel.each(root_specs.sort_by(&:name), in_threads: 10) do |spec|
24
+ if pods_to_install.include?(spec.name)
25
+ if sandbox_state.changed.include?(spec.name) && sandbox.manifest
26
+ current_version = spec.version
27
+ previous_version = sandbox.manifest.version(spec.name)
28
+ has_changed_version = current_version != previous_version
29
+ current_repo = analysis_result.specs_by_source.detect { |key, values| break key if values.map(&:name).include?(spec.name) }
30
+ current_repo &&= current_repo.url || current_repo.name
31
+ previous_spec_repo = sandbox.manifest.spec_repo(spec.name)
32
+ has_changed_repo = !previous_spec_repo.nil? && current_repo && (current_repo != previous_spec_repo)
33
+ title = "Installing #{spec.name} #{spec.version}"
34
+ title << " (was #{previous_version} and source changed to `#{current_repo}` from `#{previous_spec_repo}`)" if has_changed_version && has_changed_repo
35
+ title << " (was #{previous_version})" if has_changed_version && !has_changed_repo
36
+ title << " (source changed to `#{current_repo}` from `#{previous_spec_repo}`)" if !has_changed_version && has_changed_repo
37
+ else
38
+ title = "Installing #{spec}"
39
+ end
40
+ UI.titled_section(title.green, title_options) do
41
+ install_source_of_pod(spec.name)
42
+ end
43
+ else
44
+ UI.titled_section("Using #{spec}", title_options) do
45
+ create_pod_installer(spec.name)
46
+ end
47
+ end
48
+ end
49
+ else
50
+ old_install_pod_sources
51
+ end
52
+ end
53
+ end
54
+
55
+ module Downloader
56
+ class Cache
57
+ # 多线程锁
58
+ @@lock = Mutex.new
59
+
60
+ # 后面如果要切到进程的话,可以在 cache root 里面新建一个文件
61
+ # 利用这个文件 lock
62
+ # https://stackoverflow.com/questions/23748648/using-fileflock-as-ruby-global-lock-mutex-for-processes
63
+
64
+ # rmtree 在多进程情况下可能 Directory not empty @ dir_s_rmdir 错误
65
+ # old_ensure_matching_version 会移除不是同一个 CocoaPods 版本的组件缓存
66
+ alias_method :old_ensure_matching_version, :ensure_matching_version
67
+ def ensure_matching_version
68
+ @@lock.synchronize { old_ensure_matching_version }
69
+ end
70
+
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,29 @@
1
+
2
+ module Pod
3
+ class Specification
4
+ class Linter
5
+ # !@group Lint steps
6
+
7
+ # Checks that the spec's root name matches the filename.
8
+ #
9
+ # @return [void]
10
+ #
11
+ def validate_root_name
12
+ if spec.root.name && file
13
+ acceptable_names = [
14
+ spec.root.name + '.podspec',
15
+ spec.root.name + '.podspec.json',
16
+ # 支持 binary 后缀
17
+ spec.root.name + '.binary.podspec',
18
+ spec.root.name + '.binary.podspec.json'
19
+ ]
20
+ names_match = acceptable_names.include?(file.basename.to_s)
21
+ unless names_match
22
+ results.add_error('name', 'The name of the spec should match the ' \
23
+ 'name of the file.')
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,15 @@
1
+ require 'cocoapods-bin/native/installation_options'
2
+
3
+ module Pod
4
+ class Installer
5
+ class PodSourceInstaller
6
+ attr_accessor :installation_options
7
+
8
+ alias_method :old_verify_source_is_secure, :verify_source_is_secure
9
+ def verify_source_is_secure(root_spec)
10
+ # http source 默认不警告
11
+ old_verify_source_is_secure(root_spec) if installation_options.warn_for_unsecure_source?
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,67 @@
1
+ require 'cocoapods'
2
+
3
+ module Pod
4
+ class Podfile
5
+ USE_BINARIES = 'use_binaries'.freeze
6
+ USE_SOURCE_PODS = 'use_source_pods'.freeze
7
+ USE_BINARIES_SELECTOR = 'use_binaries_selector'.freeze
8
+ # TREAT_DEVELOPMENTS_AS_NORMAL = 'treat_developments_as_normal'.freeze
9
+
10
+ module DSL
11
+ def use_binaries!(flag = true)
12
+ set_internal_hash_value(USE_BINARIES, flag)
13
+ end
14
+
15
+ def use_binaries_with_spec_selector!(&block)
16
+ raise Informative, '必须提供选择需要二进制组件的 block !' unless block_given?
17
+
18
+ set_internal_hash_value(USE_BINARIES_SELECTOR, block)
19
+ end
20
+
21
+ def set_use_source_pods(pods)
22
+ hash_pods_use_source = get_internal_hash_value(USE_SOURCE_PODS) || []
23
+ hash_pods_use_source += Array(pods)
24
+ set_internal_hash_value(USE_SOURCE_PODS, hash_pods_use_source)
25
+ end
26
+ end
27
+
28
+ module ENVExecutor
29
+ def execute_with_use_binaries(use_binaries, &block)
30
+ execute_with_key(USE_BINARIES, -> { use_binaries ? 'true' : 'false' }, &block)
31
+ end
32
+
33
+ def execute_with_key(key, value_returner, &block)
34
+ origin_value = ENV[key]
35
+ ENV[key] = value_returner.call
36
+
37
+ yield if block_given?
38
+
39
+ ENV[key] = origin_value
40
+ end
41
+ end
42
+
43
+ extend ENVExecutor
44
+
45
+ def use_binaries_selector
46
+ get_internal_hash_value(USE_BINARIES_SELECTOR, nil)
47
+ end
48
+
49
+ def use_binaries?
50
+ get_internal_hash_value(USE_BINARIES, false) || ENV[USE_BINARIES] == 'true'
51
+ end
52
+
53
+ def use_source_pods
54
+ get_internal_hash_value(USE_SOURCE_PODS, []) + String(ENV[USE_SOURCE_PODS]).split('|').uniq
55
+ end
56
+
57
+ private
58
+ # set_hash_value 有 key 限制
59
+ def set_internal_hash_value(key, value)
60
+ internal_hash[key] = value
61
+ end
62
+
63
+ def get_internal_hash_value(key, default = nil)
64
+ internal_hash.fetch(key, default)
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,103 @@
1
+ require 'parallel'
2
+ require 'cocoapods'
3
+ require 'cocoapods-bin/native/podfile'
4
+ require 'cocoapods-bin/native/sources_manager'
5
+ require 'cocoapods-bin/native/installation_options'
6
+ require 'cocoapods-bin/gem_version'
7
+
8
+ module Pod
9
+ class Resolver
10
+ # >= 1.4.0 才有 resolver_specs_by_target 以及 ResolverSpecification
11
+ # >= 1.5.0 ResolverSpecification 才有 source,供 install 或者其他操作时,输入 source 变更
12
+ #
13
+ if Pod.match_version?('~> 1.4')
14
+ old_resolver_specs_by_target = instance_method(:resolver_specs_by_target)
15
+ define_method(:resolver_specs_by_target) do
16
+ resolver_specs_by_target = old_resolver_specs_by_target.bind(self).call()
17
+
18
+ # 过滤出用户工程
19
+ user_specs_by_target = resolver_specs_by_target.reject { |st| st.name.end_with?('_Tests') || st.name == 'Pods' }
20
+
21
+ sources_manager = Config.instance.sources_manager
22
+ use_source_pods = podfile.use_source_pods
23
+
24
+ user_specs_by_target.each do |target, rspecs|
25
+ # use_binaries 并且 use_source_pods 不包含
26
+ use_binary_rspecs = if podfile.use_binaries? || podfile.use_binaries_selector
27
+ rspecs.select do |rspec|
28
+ ([rspec.name, rspec.root.name] & use_source_pods).empty? &&
29
+ (podfile.use_binaries_selector.nil? || podfile.use_binaries_selector.call(rspec.spec))
30
+ end
31
+ else
32
+ []
33
+ end
34
+
35
+ # Parallel.map(rspecs, in_threads: 8) do |rspec|
36
+ resolver_specs_by_target[target] = rspecs.map do |rspec|
37
+ # 含有 subspecs 的组件暂不处理
38
+ # next rspec if rspec.spec.subspec? || rspec.spec.subspecs.any?
39
+
40
+ # developments 组件采用默认输入的 spec (development pods 的 source 为 nil)
41
+ next rspec unless rspec.spec.respond_to?(:spec_source) && rspec.spec.spec_source
42
+
43
+ # 采用二进制依赖并且不为开发组件
44
+ use_binary = use_binary_rspecs.include?(rspec)
45
+ source = use_binary ? sources_manager.binary_source : sources_manager.code_source
46
+
47
+ spec_version = rspec.spec.version
48
+ begin
49
+ # 从新 source 中获取 spec
50
+ specification = source.specification(rspec.root.name, spec_version)
51
+
52
+ # 组件是 subspec
53
+ specification = specification.subspec_by_name(rspec.name, false, true) if rspec.spec.subspec?
54
+ # 这里可能出现分析依赖的 source 和切换后的 source 对应 specification 的 subspec 对应不上
55
+ # 造成 subspec_by_name 返回 nil,这个是正常现象
56
+ next unless specification
57
+
58
+ # 组装新的 rspec ,替换原 rspec
59
+ rspec = if Pod.match_version?('~> 1.4.0')
60
+ ResolverSpecification.new(specification, rspec.used_by_tests_only)
61
+ else
62
+ ResolverSpecification.new(specification, rspec.used_by_tests_only, source)
63
+ end
64
+ rspec
65
+ rescue Pod::StandardError => error
66
+ # 没有从新的 source 找到对应版本组件,直接返回原 rspec
67
+ UI.message "【#{rspec.spec.name} | #{spec_version}】组件无对应二进制版本 , 将采用源码依赖." if use_binary#.yellow
68
+ rspec
69
+ end
70
+
71
+ rspec
72
+ end.compact
73
+ end
74
+
75
+ resolver_specs_by_target
76
+ end
77
+ end
78
+ end
79
+
80
+ if Pod.match_version?('~> 1.4.0')
81
+ # 1.4.0 没有 spec_source
82
+ class Specification
83
+ class Set
84
+ class LazySpecification < BasicObject
85
+ attr_reader :spec_source
86
+
87
+ old_initialize = instance_method(:initialize)
88
+ define_method(:initialize) do |name, version, source|
89
+ old_initialize.bind(self).call(name, version, source)
90
+
91
+ @spec_source = source
92
+ end
93
+
94
+ def respond_to?(method, include_all = false)
95
+ return super unless method == :spec_source
96
+ true
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
103
+