cocoapods-bin 0.0.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.
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
+