cocoapods-miBin 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/.rakeTasks +7 -0
  4. data/Gemfile +13 -0
  5. data/Gemfile.lock +104 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +522 -0
  8. data/Rakefile +13 -0
  9. data/cocoapods-miBin.gemspec +27 -0
  10. data/lib/cocoapods-miBin.rb +4 -0
  11. data/lib/cocoapods-miBin/command.rb +3 -0
  12. data/lib/cocoapods-miBin/command/bin.rb +60 -0
  13. data/lib/cocoapods-miBin/command/bin/archive.rb +134 -0
  14. data/lib/cocoapods-miBin/command/bin/init.rb +71 -0
  15. data/lib/cocoapods-miBin/command/bin/lib.rb +14 -0
  16. data/lib/cocoapods-miBin/command/bin/lib/lint.rb +69 -0
  17. data/lib/cocoapods-miBin/command/bin/list.rb +50 -0
  18. data/lib/cocoapods-miBin/command/bin/open.rb +61 -0
  19. data/lib/cocoapods-miBin/command/bin/repo.rb +15 -0
  20. data/lib/cocoapods-miBin/command/bin/repo/push.rb +116 -0
  21. data/lib/cocoapods-miBin/command/bin/repo/update.rb +42 -0
  22. data/lib/cocoapods-miBin/command/bin/search.rb +69 -0
  23. data/lib/cocoapods-miBin/command/bin/spec.rb +15 -0
  24. data/lib/cocoapods-miBin/command/bin/spec/create.rb +75 -0
  25. data/lib/cocoapods-miBin/command/bin/spec/lint.rb +111 -0
  26. data/lib/cocoapods-miBin/command/bin/umbrella.rb +55 -0
  27. data/lib/cocoapods-miBin/config/config.rb +81 -0
  28. data/lib/cocoapods-miBin/config/config_asker.rb +58 -0
  29. data/lib/cocoapods-miBin/gem_version.rb +11 -0
  30. data/lib/cocoapods-miBin/helpers.rb +5 -0
  31. data/lib/cocoapods-miBin/helpers/framework.rb +64 -0
  32. data/lib/cocoapods-miBin/helpers/framework_builder.rb +227 -0
  33. data/lib/cocoapods-miBin/helpers/sources_helper.rb +33 -0
  34. data/lib/cocoapods-miBin/helpers/spec_creator.rb +159 -0
  35. data/lib/cocoapods-miBin/helpers/spec_files_helper.rb +77 -0
  36. data/lib/cocoapods-miBin/native.rb +21 -0
  37. data/lib/cocoapods-miBin/native/acknowledgements.rb +27 -0
  38. data/lib/cocoapods-miBin/native/analyzer.rb +53 -0
  39. data/lib/cocoapods-miBin/native/installation_options.rb +26 -0
  40. data/lib/cocoapods-miBin/native/installer.rb +116 -0
  41. data/lib/cocoapods-miBin/native/linter.rb +26 -0
  42. data/lib/cocoapods-miBin/native/path_source.rb +33 -0
  43. data/lib/cocoapods-miBin/native/pod_source_installer.rb +19 -0
  44. data/lib/cocoapods-miBin/native/pod_target.rb +8 -0
  45. data/lib/cocoapods-miBin/native/podfile.rb +79 -0
  46. data/lib/cocoapods-miBin/native/podfile_env.rb +36 -0
  47. data/lib/cocoapods-miBin/native/podspec_finder.rb +25 -0
  48. data/lib/cocoapods-miBin/native/resolver.rb +200 -0
  49. data/lib/cocoapods-miBin/native/sandbox_analyzer.rb +34 -0
  50. data/lib/cocoapods-miBin/native/source.rb +35 -0
  51. data/lib/cocoapods-miBin/native/sources_manager.rb +20 -0
  52. data/lib/cocoapods-miBin/native/specification.rb +31 -0
  53. data/lib/cocoapods-miBin/native/validator.rb +16 -0
  54. data/lib/cocoapods-miBin/source_provider_hook.rb +21 -0
  55. data/lib/cocoapods_plugin.rb +5 -0
  56. data/spec/command/bin_spec.rb +12 -0
  57. data/spec/spec_helper.rb +50 -0
  58. metadata +173 -0
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cocoapods-miBin/native/sources_manager.rb'
4
+
5
+ module CBin
6
+ module SourcesHelper
7
+ def sources_manager
8
+ Pod::Config.instance.sources_manager
9
+ end
10
+
11
+ def binary_source
12
+ sources_manager.binary_source
13
+ end
14
+
15
+ def code_source
16
+ sources_manager.code_source
17
+ end
18
+
19
+ # 优先采用对应依赖的 source
20
+ # cocoapods 内部会先匹配前面符合的 specification
21
+ # 只允许二进制的 specification subspec 比源码的 specification subspec 多
22
+ #
23
+ def valid_sources(code_dependencies = false)
24
+ sources = [binary_source, code_source]
25
+ sources.reverse! if code_dependencies
26
+ sources
27
+ end
28
+
29
+ def sources_option(code_dependencies, additional_sources)
30
+ (valid_sources(code_dependencies).map(&:url) + Array(additional_sources)).join(',')
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,159 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cocoapods'
4
+ require 'cocoapods-miBin/config/config'
5
+
6
+ module CBin
7
+ class Specification
8
+ class Creator
9
+ attr_reader :code_spec
10
+ attr_reader :template_spec
11
+ attr_reader :spec
12
+
13
+ def initialize(code_spec, template_spec, platforms = 'ios')
14
+ @code_spec = code_spec
15
+ @template_spec = template_spec
16
+ @platforms = Array(platforms)
17
+ validate!
18
+ end
19
+
20
+ def validate!
21
+ raise Pod::Informative, '源码 podspec 不能为空 .' unless code_spec
22
+ if code_spec.subspecs.any? && template_spec.nil?
23
+ raise Pod::Informative, "不支持自动生成存在 subspec 的二进制 podspec , 需要提供模版文件 #{code_spec.name}.binary.podspec.template ."
24
+ end
25
+ end
26
+
27
+ def create
28
+ spec = template_spec ? create_from_code_spec_and_template_spec : create_from_code_spec
29
+
30
+ Pod::UI.message '生成二进制 podspec 内容: '
31
+ spec.to_pretty_json.split("\n").each do |text|
32
+ Pod::UI.message text
33
+ end
34
+
35
+ spec
36
+ end
37
+
38
+ def write_spec_file(file = filename)
39
+ create unless spec
40
+
41
+ File.open(file, 'w+') do |f|
42
+ f.write(spec.to_pretty_json)
43
+ end
44
+
45
+ @filename = file
46
+ end
47
+
48
+ def clear_spec_file
49
+ File.delete(filename) if File.exist?(filename)
50
+ end
51
+
52
+ def filename
53
+ @filename ||= "#{spec.name}.binary.podspec.json"
54
+ end
55
+
56
+ private
57
+
58
+ def create_from_code_spec
59
+ @spec = code_spec.dup
60
+ # vendored_frameworks | resources | source | source_files | public_header_files
61
+ # license | resource_bundles | vendored_libraries
62
+ #
63
+ #vi = @spec.vendored_libraries
64
+ file_accessor = Pod::Sandbox::FileAccessor.new(Pathname.new('.').expand_path, code_spec_consumer)
65
+ vendored_static_libraries = file_accessor.vendored_static_libraries
66
+ vendored_static_frameworks = file_accessor.vendored_static_frameworks
67
+ #puts Pathname.new('.').expand_path
68
+ #puts code_spec_consumer
69
+ #puts vi
70
+
71
+ # Project Linkin
72
+ base_framework = ["#{spec.name}_binary/#{code_spec.root.name}.framework"]
73
+ vendored_static_frameworks.each do |framework|
74
+ #puts framework.class
75
+ base_framework.append("#{spec.name}_binary/"+File.basename(framework))
76
+ end
77
+ @spec.vendored_frameworks = base_framework
78
+ # Resources
79
+ extnames = []
80
+ extnames << '*.bundle' if code_spec_consumer.resource_bundles.any?
81
+ if code_spec_consumer.resources.any?
82
+ extnames += code_spec_consumer.resources.map { |r| File.basename(r) }
83
+ end
84
+ if extnames.any?
85
+ #@spec.resources = framework_contents('Resources').flat_map { |r| extnames.map { |e| "#{r}/#{e}" } }
86
+ @spec.resources = framework_resources.flat_map { |r| extnames.map { |e| "#{r}/#{e}" } }
87
+ end
88
+
89
+ base_libs = []
90
+ vendored_static_libraries.each do |lib|
91
+ #puts framework.class
92
+ base_libs.append("#{spec.name}_binary/"+File.basename(lib))
93
+ end
94
+ if base_libs.count > 0
95
+ @spec.vendored_libraries = base_libs
96
+ end
97
+
98
+ # Source Location
99
+ @spec.source = binary_source
100
+
101
+ # Source Code
102
+ @spec.source_files = framework_contents('Headers/*')
103
+ @spec.public_header_files = framework_contents('Headers/*')
104
+
105
+ # Unused for binary
106
+ spec_hash = @spec.to_hash
107
+ # spec_hash.delete('license')
108
+ spec_hash.delete('resource_bundles')
109
+ spec_hash.delete('exclude_files')
110
+ spec_hash.delete('preserve_paths')
111
+ spec_hash.delete('source_files')
112
+ spec_hash.delete('public_header_files')
113
+ # 这里不确定 vendored_libraries 指定的时动态/静态库
114
+ # 如果是静态库的话,需要移除,否则就不移除
115
+ # 最好是静态库都独立成 Pod ,cocoapods-package 打静态库去 collect 目标文件时好做过滤
116
+ # 这里统一只对命名后缀 .a 文件做处理
117
+ # spec_hash.delete('vendored_libraries')
118
+ # libraries 只能假设为动态库不做处理了,如果有例外,需要开发者自行处理
119
+
120
+ #vendored_libraries = spec_hash.delete('vendored_libraries')
121
+ #vendored_libraries = Array(vendored_libraries).reject { |l| l.end_with?('.a') }
122
+ #if vendored_libraries.any?
123
+ # spec_hash['vendored_libraries'] = vendored_libraries
124
+ #end
125
+
126
+ # Filter platforms
127
+ platforms = spec_hash['platforms']
128
+ selected_platforms = platforms.select { |k, _v| @platforms.include?(k) }
129
+ spec_hash['platforms'] = selected_platforms.empty? ? platforms : selected_platforms
130
+
131
+ @spec = Pod::Specification.from_hash(spec_hash)
132
+ @spec
133
+ end
134
+
135
+ def create_from_code_spec_and_template_spec
136
+ @spec = template_spec.dup
137
+
138
+ @spec.version = code_spec.version
139
+ @spec.source = binary_source
140
+ @spec
141
+ end
142
+
143
+ def binary_source
144
+ { http: format(CBin.config.binary_download_url, code_spec.root.name, code_spec.version, code_spec.root.name ), type: CBin.config.download_file_type }
145
+ end
146
+
147
+ def code_spec_consumer(_platform = :ios)
148
+ code_spec.consumer(:ios)
149
+ end
150
+
151
+ def framework_contents(name)
152
+ ["#{code_spec.root.name}.framework", "#{code_spec.root.name}.framework/Versions/A"].map { |path| "#{path}/#{name}" }
153
+ end
154
+ def framework_resources()
155
+ ["#{spec.name}_binary/#{code_spec.root.name}.framework", "#{spec.name}_binary/#{code_spec.root.name}.framework/Versions/A"].map { |path| "#{path}" }
156
+ end
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cocoapods-miBin/native/sources_manager.rb'
4
+ require 'cocoapods-miBin/helpers/spec_creator'
5
+
6
+ module CBin
7
+ module SpecFilesHelper
8
+ def spec_files
9
+ @spec_files ||= Pathname.glob('*.podspec{,.json}')
10
+ end
11
+
12
+ def binary_spec_files
13
+ @binary_spec_files ||= Pathname.glob('*.binary.podspec{,.json}')
14
+ end
15
+
16
+ def binary_template_spec_files
17
+ @binary_spec_template_files ||= Pathname.glob('*.binary-template.podspec{,.json}')
18
+ end
19
+
20
+ def binary_template_spec_file
21
+ @binary_spec_template_file ||= binary_template_spec_files.first
22
+ end
23
+
24
+ def code_spec_files
25
+ @code_spec_files ||= spec_files - binary_spec_files - binary_template_spec_files
26
+ end
27
+
28
+ def code_spec
29
+ if code_spec_files.first
30
+ Pod::Specification.from_file(code_spec_files.first)
31
+ end
32
+ end
33
+
34
+ def binary_spec
35
+ if binary_spec_files.first
36
+ Pod::Specification.from_file(binary_spec_files.first)
37
+ end
38
+ end
39
+
40
+ def binary_template_spec
41
+ if binary_template_spec_file
42
+ Pod::Specification.from_file(binary_template_spec_file)
43
+ end
44
+ end
45
+
46
+ def find_spec_file(podspec)
47
+ path = Pathname(podspec)
48
+ raise Pod::Informative, "无法找到 #{podspec}" unless path.exist?
49
+
50
+ path
51
+ end
52
+
53
+ def create_binary_spec_file(code_spec, template_spec)
54
+ # 1. code spec 是否有 subpsec
55
+ # 1.1 有,查找 template spec,并生成
56
+ # 1.2 没有,是否有 template spec
57
+ # 1.2.1 有,根据 template spec 生成
58
+ # 1.2.2 没有,根据 code spec 生成
59
+
60
+ unless code_spec
61
+ raise Pod::Informative, '没有二进制 podspec 的情况下,必须要提供源码 podspec.'
62
+ end
63
+ if code_spec.subspecs.any? && template_spec.nil?
64
+ raise Pod::Informative, '拥有 subspec 的组件,在生成二进制 podspec 时,必须要提供模版 podspec.'
65
+ end
66
+
67
+ @spec_creator = CBin::Specification::Creator.new(code_spec, template_spec)
68
+ @spec_creator.create
69
+ @spec_creator.write_spec_file
70
+ @spec_creator.filename
71
+ end
72
+
73
+ def clear_binary_spec_file_if_needed
74
+ @spec_creator&.clear_spec_file
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cocoapods'
4
+
5
+ if Pod.match_version?('~> 1.4')
6
+ require 'cocoapods-miBin/native/podfile'
7
+ require 'cocoapods-miBin/native/installation_options'
8
+ require 'cocoapods-miBin/native/specification'
9
+ require 'cocoapods-miBin/native/path_source'
10
+ require 'cocoapods-miBin/native/analyzer'
11
+ require 'cocoapods-miBin/native/installer'
12
+ require 'cocoapods-miBin/native/pod_source_installer'
13
+ require 'cocoapods-miBin/native/linter'
14
+ require 'cocoapods-miBin/native/resolver'
15
+ require 'cocoapods-miBin/native/pod_target'
16
+ require 'cocoapods-miBin/native/source'
17
+ require 'cocoapods-miBin/native/validator'
18
+ require 'cocoapods-miBin/native/acknowledgements'
19
+ require 'cocoapods-miBin/native/sandbox_analyzer'
20
+ require 'cocoapods-miBin/native/podspec_finder'
21
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pod
4
+ module Generator
5
+ class Acknowledgements
6
+ def license_text(spec)
7
+ return nil unless spec.license
8
+
9
+ text = spec.license[:text]
10
+ unless text
11
+ if license_file = spec.license[:file]
12
+ license_path = file_accessor(spec).root + license_file
13
+ if File.exist?(license_path)
14
+ text = IO.read(license_path)
15
+ else
16
+ # UI.warn "Unable to read the license file `#{license_file}` " \
17
+ # "for the spec `#{spec}`"
18
+ end
19
+ elsif license_file = file_accessor(spec).license
20
+ text = IO.read(license_file)
21
+ end
22
+ end
23
+ text
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'parallel'
4
+ require 'cocoapods'
5
+
6
+ module Pod
7
+ class Installer
8
+ class Analyzer
9
+ # > 1.6.0
10
+ # all_specs[dep.name] 为 nil 会崩溃
11
+ # 主要原因是 all_specs 分析错误
12
+ # 查看 source 是否正确
13
+ #
14
+ # def dependencies_for_specs(specs, platform, all_specs)
15
+ # return [] if specs.empty? || all_specs.empty?
16
+
17
+ # dependent_specs = Set.new
18
+
19
+ # specs.each do |s|
20
+ # s.dependencies(platform).each do |dep|
21
+ # all_specs[dep.name].each do |spec|
22
+ # dependent_specs << spec
23
+ # end
24
+ # end
25
+ # end
26
+
27
+ # dependent_specs - specs
28
+ # end
29
+
30
+ # > 1.5.3 版本
31
+ # rewrite update_repositories
32
+ #
33
+ alias old_update_repositories update_repositories
34
+ def update_repositories
35
+ if installation_options.update_source_with_multi_processes
36
+ # 并发更新私有源
37
+ # 这里多线程会导致 pod update 额外输出 --verbose 的内容
38
+ # 不知道为什么?
39
+ Parallel.each(sources.uniq(&:url), in_processes: 4) do |source|
40
+ if source.git?
41
+ config.sources_manager.update(source.name, true)
42
+ else
43
+ UI.message "Skipping `#{source.name}` update because the repository is not a git source repository."
44
+ end
45
+ end
46
+ @specs_updated = true
47
+ else
48
+ old_update_repositories
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cocoapods'
4
+
5
+ module Pod
6
+ class Installer
7
+ class InstallationOptions
8
+ def self.env_option(key, default = true)
9
+ option key, ENV[key.to_s].nil? ? default : ENV[key.to_s] == 'true'
10
+ end
11
+
12
+ # 不同 source 存在相同 spec 名时,默认不警告
13
+ defaults.delete('warn_for_multiple_pod_sources')
14
+ env_option :warn_for_multiple_pod_sources, false
15
+
16
+ # 是否警告不安全 source (如 http )
17
+ env_option :warn_for_unsecure_source, false
18
+
19
+ # 是否多线程执行 install_pod_sources
20
+ env_option :install_with_multi_threads, true
21
+
22
+ # 是否多进程执行 update_repositories
23
+ env_option :update_source_with_multi_processes, true
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'parallel'
4
+ require 'cocoapods'
5
+ require 'cocoapods-miBin/native/pod_source_installer'
6
+
7
+ module Pod
8
+ class Installer
9
+ alias old_create_pod_installer create_pod_installer
10
+ def create_pod_installer(pod_name)
11
+ installer = old_create_pod_installer(pod_name)
12
+ installer.installation_options = installation_options
13
+ installer
14
+ end
15
+
16
+ alias old_install_pod_sources install_pod_sources
17
+ def install_pod_sources
18
+ if installation_options.install_with_multi_threads
19
+ if Pod.match_version?('~> 1.4.0')
20
+ install_pod_sources_for_version_in_1_4_0
21
+ elsif Pod.match_version?('~> 1.5')
22
+ install_pod_sources_for_version_above_1_5_0
23
+ else
24
+ old_install_pod_sources
25
+ end
26
+ else
27
+ old_install_pod_sources
28
+ end
29
+ end
30
+
31
+ # rewrite install_pod_sources
32
+ def install_pod_sources_for_version_in_1_4_0
33
+ @installed_specs = []
34
+ pods_to_install = sandbox_state.added | sandbox_state.changed
35
+ title_options = { verbose_prefix: '-> '.green }
36
+ Parallel.each(root_specs.sort_by(&:name), in_threads: 4) do |spec|
37
+ if pods_to_install.include?(spec.name)
38
+ if sandbox_state.changed.include?(spec.name) && sandbox.manifest
39
+ previous = sandbox.manifest.version(spec.name)
40
+ title = "Installing #{spec.name} #{spec.version} (was #{previous})"
41
+ else
42
+ title = "Installing #{spec}"
43
+ end
44
+ UI.titled_section(title.green, title_options) do
45
+ install_source_of_pod(spec.name)
46
+ end
47
+ else
48
+ UI.titled_section("Using #{spec}", title_options) do
49
+ create_pod_installer(spec.name)
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ def install_pod_sources_for_version_above_1_5_0
56
+ @installed_specs = []
57
+ pods_to_install = sandbox_state.added | sandbox_state.changed
58
+ title_options = { verbose_prefix: '-> '.green }
59
+ # 多进程下载,多线程时 log 会显著交叉,多进程好点,但是多进程需要利用文件锁对 cache 进行保护
60
+ # in_processes: 10
61
+ Parallel.each(root_specs.sort_by(&:name), in_threads: 4) do |spec|
62
+ if pods_to_install.include?(spec.name)
63
+ if sandbox_state.changed.include?(spec.name) && sandbox.manifest
64
+ current_version = spec.version
65
+ previous_version = sandbox.manifest.version(spec.name)
66
+ has_changed_version = current_version != previous_version
67
+ current_repo = analysis_result.specs_by_source.detect do |key, values|
68
+ break key if values.map(&:name).include?(spec.name)
69
+ end
70
+ current_repo &&= current_repo.url || current_repo.name
71
+ previous_spec_repo = sandbox.manifest.spec_repo(spec.name)
72
+ has_changed_repo = !previous_spec_repo.nil? && current_repo && (current_repo != previous_spec_repo)
73
+ title = "Installing #{spec.name} #{spec.version}".dup
74
+ #puts title.frozen?
75
+ if has_changed_version && has_changed_repo
76
+ title << " (was #{previous_version} and source changed to `#{current_repo}` from `#{previous_spec_repo}`)"
77
+ end
78
+ if has_changed_version && !has_changed_repo
79
+ title << " (was #{previous_version})"
80
+ end
81
+ if !has_changed_version && has_changed_repo
82
+ title << " (source changed to `#{current_repo}` from `#{previous_spec_repo}`)"
83
+ end
84
+ else
85
+ title = "Installing #{spec}"
86
+ end
87
+ UI.titled_section(title.green, title_options) do
88
+ install_source_of_pod(spec.name)
89
+ end
90
+ else
91
+ UI.titled_section("Using #{spec}", title_options) do
92
+ create_pod_installer(spec.name)
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
98
+
99
+ module Downloader
100
+ class Cache
101
+ # 多线程锁
102
+ @@lock = Mutex.new
103
+
104
+ # 后面如果要切到进程的话,可以在 cache root 里面新建一个文件
105
+ # 利用这个文件 lock
106
+ # https://stackoverflow.com/questions/23748648/using-fileflock-as-ruby-global-lock-mutex-for-processes
107
+
108
+ # rmtree 在多进程情况下可能 Directory not empty @ dir_s_rmdir 错误
109
+ # old_ensure_matching_version 会移除不是同一个 CocoaPods 版本的组件缓存
110
+ alias old_ensure_matching_version ensure_matching_version
111
+ def ensure_matching_version
112
+ @@lock.synchronize { old_ensure_matching_version }
113
+ end
114
+ end
115
+ end
116
+ end