cocoapods-binary-matchup 0.0.30 → 0.0.32

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.
@@ -0,0 +1,255 @@
1
+ require_relative 'rome/build_framework'
2
+ require_relative 'helper/passer'
3
+ require_relative 'helper/target_checker'
4
+
5
+
6
+ # patch prebuild ability
7
+ module Pod
8
+ class Installer
9
+
10
+
11
+ private
12
+
13
+ def local_manifest
14
+ if not @local_manifest_inited
15
+ @local_manifest_inited = true
16
+ raise "This method should be call before generate project" unless self.analysis_result == nil
17
+ @local_manifest = self.sandbox.manifest
18
+ end
19
+ @local_manifest
20
+ end
21
+
22
+ # @return [Analyzer::SpecsState]
23
+ def prebuild_pods_changes
24
+ return nil if local_manifest.nil?
25
+ UI.puts "--------------------------------"
26
+ UI.puts "prebuild_pods_changes"
27
+ UI.puts "--------------------------------"
28
+ if @prebuild_pods_changes.nil?
29
+ # detect the changes with podfile by manifest.lock
30
+ changes = local_manifest.detect_changes_with_podfile(podfile)
31
+ @prebuild_pods_changes = Analyzer::SpecsState.new(changes)
32
+ # save the chagnes info for later stage
33
+ Pod::Prebuild::Passer.prebuild_pods_changes = @prebuild_pods_changes
34
+ end
35
+ @prebuild_pods_changes
36
+ end
37
+
38
+
39
+ public
40
+
41
+ # check if need to prebuild
42
+ def have_exact_prebuild_cache?
43
+ # check if need build frameworks
44
+ return false if local_manifest == nil
45
+
46
+ changes = prebuild_pods_changes
47
+ added = changes.added
48
+ changed = changes.changed
49
+ unchanged = changes.unchanged
50
+ deleted = changes.deleted
51
+
52
+ unchange_framework_names = (added + unchanged)
53
+
54
+ exsited_framework_names = sandbox.exsited_framework_names
55
+ missing = unchanged.select do |pod_name|
56
+ not exsited_framework_names.include?(pod_name)
57
+ end
58
+
59
+ needed = (added + changed + deleted + missing)
60
+ return needed.empty?
61
+ end
62
+
63
+
64
+ # The install method when have completed cache
65
+ def install_when_cache_hit!
66
+ # just print log
67
+ self.sandbox.exsited_framework_names.each do |name|
68
+ UI.puts "Using #{name}"
69
+ end
70
+ end
71
+
72
+
73
+ # Build the needed framework files
74
+ def prebuild_frameworks!
75
+
76
+ # check
77
+ # give a early warning, instead of after compiling all the pods
78
+ Prebuild.check_one_pod_should_have_only_one_target(self.pod_targets)
79
+
80
+ # build options
81
+ sandbox_path = sandbox.root
82
+ existed_framework_folder = sandbox.generate_framework_path
83
+ bitcode_enabled = Pod::Podfile::DSL.bitcode_enabled
84
+ targets = []
85
+
86
+ if local_manifest != nil
87
+
88
+ changes = prebuild_pods_changes
89
+ added = changes.added
90
+ changed = changes.changed
91
+ unchanged = changes.unchanged
92
+ deleted = changes.deleted
93
+
94
+ existed_framework_folder.mkdir unless existed_framework_folder.exist?
95
+ exsited_framework_names = sandbox.exsited_framework_names
96
+
97
+ # additions
98
+ missing = unchanged.select do |pod_name|
99
+ not exsited_framework_names.include?(pod_name)
100
+ end
101
+
102
+ root_names_to_update = (added + changed + missing)
103
+
104
+ # transform names to targets
105
+ name_to_target_hash = self.pod_targets.reduce({}) do |sum, target|
106
+ sum[target.name] = target
107
+ sum
108
+ end
109
+ targets = root_names_to_update.map do |root_name|
110
+ t = name_to_target_hash[root_name]
111
+ raise "There's no target named (#{root_name}) in Pod.xcodeproj.\n #{name_to_target_hash.keys}" if t.nil?
112
+ t
113
+ end || []
114
+
115
+ # add the dendencies
116
+ dependency_targets = targets.map {|t| t.recursive_dependent_targets }.flatten.uniq || []
117
+ targets = (targets + dependency_targets).uniq
118
+ else
119
+ targets = self.pod_targets
120
+ end
121
+
122
+ targets = targets.reject {|pod_target| sandbox.local?(pod_target.pod_name) }
123
+
124
+ Pod::PrebuildCache::Cache.remove_all_invalid_cache(sandbox, targets)
125
+
126
+ # build!
127
+ Pod::UI.puts "Prebuild frameworks (total #{targets.count})"
128
+ Pod::Prebuild.remove_build_dir(sandbox_path)
129
+ targets.each do |target|
130
+ # If target shouldn't build, we copy all the original files
131
+ # This is for target with only .a and .h files
132
+ if !target.should_build?
133
+ UI.puts "Prebuilding #{target.label}"
134
+ next
135
+ end
136
+
137
+ standard_sandbox_path = sandbox.standard_sanbox_path
138
+ Pod::UI.puts "📦 [#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}] Prebuild Start pod: #{target.pod_name}"
139
+ if Pod::PrebuildCache::Cache.restore_from_pod_cache(target.pod_name, sandbox)
140
+ output_path = sandbox.framework_folder_path_for_pod_name(target.name)
141
+ if prebuild_resource_bundles_missing?(target, output_path)
142
+ Pod::UI.puts "⚠️ Cached #{target.pod_name} missing resource_bundles; rebuilding..."
143
+ output_path.rmtree if output_path.exist?
144
+ else
145
+ Pod::UI.puts "📦 [#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}] Using exact cache from ~/.PodCache"
146
+ next
147
+ end
148
+ end
149
+ Pod::UI.puts "📦 [#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}] Prebuild End pod: #{target.pod_name}"
150
+
151
+ output_path = sandbox.framework_folder_path_for_pod_name(target.name)
152
+ output_path.mkpath unless output_path.exist?
153
+ Pod::Prebuild.build(sandbox_path, target, output_path, bitcode_enabled, Podfile::DSL.custom_build_options, Podfile::DSL.custom_build_options_simulator)
154
+
155
+ # save the resource paths for later installing
156
+ if target.static_framework? and !target.resource_paths.empty?
157
+ framework_path = output_path + target.framework_name
158
+ standard_sandbox_path = sandbox.standard_sanbox_path
159
+
160
+ resources = begin
161
+ if Pod::VERSION.start_with? "1.5"
162
+ target.resource_paths
163
+ else
164
+ # resource_paths is Hash{String=>Array<String>} on 1.6 and above
165
+ # (use AFNetworking to generate a demo data)
166
+ # https://github.com/leavez/cocoapods-binary/issues/50
167
+ target.resource_paths.values.flatten
168
+ end
169
+ end
170
+ raise "Wrong type: #{resources}" unless resources.kind_of? Array
171
+
172
+ path_objects = resources.map do |path|
173
+ object = Prebuild::Passer::ResourcePath.new
174
+ object.real_file_path = framework_path + File.basename(path)
175
+ object.target_file_path = path.gsub('${PODS_ROOT}', standard_sandbox_path.to_s) if path.start_with? '${PODS_ROOT}'
176
+ object.target_file_path = path.gsub("${PODS_CONFIGURATION_BUILD_DIR}", standard_sandbox_path.to_s) if path.start_with? "${PODS_CONFIGURATION_BUILD_DIR}"
177
+ object
178
+ end
179
+ Prebuild::Passer.resources_to_copy_for_static_framework[target.name] = path_objects
180
+ end
181
+ end
182
+ Pod::Prebuild.remove_build_dir(sandbox_path)
183
+
184
+
185
+ # copy vendored libraries and frameworks
186
+ targets.each do |target|
187
+ root_path = self.sandbox.pod_dir(target.name)
188
+ target_folder = sandbox.framework_folder_path_for_pod_name(target.name)
189
+
190
+ # If target shouldn't build, we copy all the original files
191
+ # This is for target with only .a and .h files
192
+ if not target.should_build?
193
+ Prebuild::Passer.target_names_to_skip_integration_framework << target.pod_name
194
+ FileUtils.cp_r(root_path, target_folder, :remove_destination => true)
195
+ next
196
+ end
197
+
198
+ # copy the vendored frameworks and libraries in _Prebuild to Pods/
199
+ target.spec_consumers.each do |consumer|
200
+ file_accessor = Sandbox::FileAccessor.new(root_path, consumer)
201
+ lib_paths = file_accessor.vendored_frameworks || []
202
+ lib_paths += file_accessor.vendored_libraries
203
+ # @TODO dSYM files
204
+ lib_paths.each do |lib_path|
205
+ relative = lib_path.relative_path_from(root_path)
206
+ destination = target_folder + relative
207
+ destination.dirname.mkpath unless destination.dirname.exist?
208
+ FileUtils.cp_r(lib_path, destination, :remove_destination => true)
209
+ end
210
+ end
211
+ end
212
+
213
+ # save the manifest.lock to cache
214
+ Pod::PrebuildCache::Cache.save_manifest_to_cache(sandbox)
215
+
216
+ # Remove useless files
217
+ # remove useless pods
218
+ all_needed_names = self.pod_targets.map(&:name).uniq
219
+ useless_names = sandbox.exsited_framework_names.reject do |name|
220
+ all_needed_names.include? name
221
+ end
222
+ useless_names.each do |name|
223
+ path = sandbox.framework_folder_path_for_pod_name(name)
224
+ path.rmtree if path.exist?
225
+ end
226
+
227
+ if not Podfile::DSL.dont_remove_source_code
228
+ # only keep manifest.lock and framework folder in _Prebuild
229
+ to_remain_files = ["Manifest.lock", File.basename(existed_framework_folder)]
230
+ to_delete_files = sandbox_path.children.select do |file|
231
+ filename = File.basename(file)
232
+ not to_remain_files.include?(filename)
233
+ end
234
+ to_delete_files.each do |path|
235
+ path.rmtree if path.exist?
236
+ end
237
+ else
238
+ # just remove the tmp files
239
+ path = sandbox.root + 'Manifest.lock.tmp'
240
+ path.rmtree if path.exist?
241
+ end
242
+
243
+ end
244
+
245
+ # patch the post install hook
246
+ old_method2 = instance_method(:run_plugins_post_install_hooks)
247
+ define_method(:run_plugins_post_install_hooks) do
248
+ old_method2.bind(self).()
249
+ if Pod::is_prebuild_stage
250
+ self.prebuild_frameworks!
251
+ end
252
+ end
253
+
254
+ end
255
+ end
@@ -0,0 +1,3 @@
1
+ module CocoapodsBinary
2
+ VERSION = "0.0.32"
3
+ end
@@ -0,0 +1,109 @@
1
+ require_relative '../tool/tool'
2
+ require_relative 'prebuild_sandbox'
3
+
4
+ module Pod
5
+
6
+ # a flag that indicate stages
7
+ class_attr_accessor :is_prebuild_stage
8
+
9
+
10
+ # a switch for the `pod` DSL to make it only valid for ':binary => true'
11
+ class Podfile
12
+ module DSL
13
+
14
+ @@enable_prebuild_patch = false
15
+
16
+ # when enable, `pod` function will skip all pods without 'prebuild => true'
17
+ def self.enable_prebuild_patch(value)
18
+ @@enable_prebuild_patch = value
19
+ end
20
+
21
+ # --- patch ---
22
+ # filter the pods that should be prebuild(all_binary! or binary => true),remember the pod is must remote pod
23
+ # this will be effective when enable_prebuild_patch is true(the binary prebuild step)
24
+ # when in system step, the enable_prebuild_patch is false, so the original method will be called
25
+ old_method = instance_method(:pod)
26
+ define_method(:pod) do |name, *args|
27
+ # if not enable, just call the original method
28
+ if !@@enable_prebuild_patch
29
+ old_method.bind(self).(name, *args)
30
+ return
31
+ end
32
+
33
+ # patched content
34
+ should_prebuild = Pod::Podfile::DSL.prebuild_all
35
+ local = false
36
+
37
+ options = args.last
38
+ if options.is_a?(Hash) and options[Pod::Prebuild.keyword] != nil
39
+ should_prebuild = options[Pod::Prebuild.keyword]
40
+ local = (options[:path] != nil)
41
+ end
42
+
43
+ if should_prebuild and (not local)
44
+ if current_target_definition.platform == :watchos
45
+ # watchos isn't supported currently
46
+ Pod::UI.warn "Binary doesn't support watchos currently: #{name}. You can manually set `binary => false` for this pod to suppress this warning."
47
+ return
48
+ end
49
+ old_method.bind(self).(name, *args)
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+
56
+ # a force disable option for integral
57
+ class Installer
58
+ def self.force_disable_integration(value)
59
+ @@force_disable_integration = value
60
+ end
61
+
62
+ # prebuild step's purpose is to build source target code or copy the prebuild framework to the target,
63
+ # so we need to disable the original method
64
+ old_method = instance_method(:integrate_user_project)
65
+ define_method(:integrate_user_project) do
66
+ if @@force_disable_integration
67
+ return
68
+ end
69
+ old_method.bind(self).()
70
+ end
71
+ end
72
+
73
+ # a option to disable install complete message
74
+ class Installer
75
+ def self.disable_install_complete_message(value)
76
+ @@disable_install_complete_message = value
77
+ end
78
+
79
+ old_method = instance_method(:print_post_install_message)
80
+ define_method(:print_post_install_message) do
81
+ if @@disable_install_complete_message
82
+ return
83
+ end
84
+ old_method.bind(self).()
85
+ end
86
+ end
87
+
88
+ # option to disable write lockfiles
89
+ class Config
90
+
91
+ @@force_disable_write_lockfile = false
92
+ def self.force_disable_write_lockfile(value)
93
+ @@force_disable_write_lockfile = value
94
+ end
95
+
96
+ old_method = instance_method(:lockfile_path)
97
+ define_method(:lockfile_path) do
98
+ if @@force_disable_write_lockfile
99
+ # As config is a singleton, sandbox_root refer to the standard sandbox.
100
+ manifest_lock_path = PrebuildSandbox.from_standard_sanbox_path(sandbox_root).root + 'Manifest.lock.tmp'
101
+ UI.puts "manifest_lock_path: #{manifest_lock_path}"
102
+ return manifest_lock_path
103
+ else
104
+ return old_method.bind(self).()
105
+ end
106
+ end
107
+ end
108
+
109
+ end
@@ -0,0 +1,41 @@
1
+ require_relative '../tool/tool'
2
+
3
+ module Pod
4
+ class Prebuild
5
+
6
+ # Pass the data between the 2 steps
7
+ #
8
+ # At step 2, the normal pod install, it needs some info of the
9
+ # prebuilt step. So we store it here.
10
+ #
11
+ class Passer
12
+
13
+ # indicate the add/remove/update of prebuit pods
14
+ # @return [Analyzer::SpecsState]
15
+ #
16
+ class_attr_accessor :prebuild_pods_changes
17
+
18
+
19
+ # represent the path of resurces to copy
20
+ class ResourcePath
21
+ attr_accessor :real_file_path
22
+ attr_accessor :target_file_path
23
+ end
24
+ # Save the resoures for static framework, and used when installing the prebuild framework
25
+ # static framework needs copy the resurces mannully
26
+ #
27
+ # @return [Hash<String, [Passer::ResourcePath]>]
28
+ class_attr_accessor :resources_to_copy_for_static_framework
29
+ self.resources_to_copy_for_static_framework = {}
30
+
31
+ # Some pod won't be build in prebuild stage even if it have `binary=>true`.
32
+ # The targets of this pods have `oshould_build? == true`.
33
+ # We should skip integration (patch spec) for this pods
34
+ #
35
+ # @return [Array<String>]
36
+ class_attr_accessor :target_names_to_skip_integration_framework
37
+ self.target_names_to_skip_integration_framework = []
38
+
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,122 @@
1
+ module Pod
2
+
3
+ class Prebuild
4
+ def self.keyword
5
+ :binary
6
+ end
7
+ end
8
+
9
+ class Podfile
10
+ class TargetDefinition
11
+
12
+ ## --- option for setting using prebuild framework ---
13
+ def parse_prebuild_framework(name, requirements)
14
+ should_prebuild = Pod::Podfile::DSL.prebuild_all
15
+
16
+ options = requirements.last
17
+ # 如果options是hash,并且包含Pod::Prebuild.keyword,则设置should_prebuild为true
18
+ if options.is_a?(Hash) && options[Pod::Prebuild.keyword] != nil
19
+ # [DINetwork', { :binary => true, :configurations => ['Debug'] }]
20
+ should_prebuild = options.delete(Pod::Prebuild.keyword)
21
+ # [DINetwork', { :configurations => ['Debug'] }],避免干扰其他配置,不删除可能让后续cocoapods本身解析报错
22
+ requirements.pop if options.empty?
23
+ end
24
+
25
+ pod_name = Specification.root_name(name)
26
+ set_prebuild_for_pod(pod_name, should_prebuild)
27
+ end
28
+
29
+ def set_prebuild_for_pod(pod_name, should_prebuild)
30
+
31
+ if should_prebuild == true
32
+ # watchos isn't supported currently
33
+ return if self.platform == :watchos
34
+
35
+ @prebuild_framework_names ||= []
36
+ @prebuild_framework_names.push pod_name
37
+ else
38
+ @should_not_prebuild_framework_names ||= []
39
+ @should_not_prebuild_framework_names.push pod_name
40
+ end
41
+ end
42
+
43
+ def prebuild_framework_names
44
+ names = @prebuild_framework_names || []
45
+ if parent != nil and parent.kind_of? TargetDefinition
46
+ names += parent.prebuild_framework_names
47
+ end
48
+ names
49
+ end
50
+ def should_not_prebuild_framework_names
51
+ names = @should_not_prebuild_framework_names || []
52
+ if parent != nil and parent.kind_of? TargetDefinition
53
+ names += parent.should_not_prebuild_framework_names
54
+ end
55
+ names
56
+ end
57
+
58
+ # ---- patch method ----
59
+ # We want modify `store_pod` method, but it's hard to insert a line in the
60
+ # implementation. So we patch a method called in `store_pod`.
61
+ # use this method to parse prebuild framework(:binary => true)
62
+ old_method = instance_method(:parse_inhibit_warnings)
63
+
64
+ define_method(:parse_inhibit_warnings) do |name, requirements|
65
+ parse_prebuild_framework(name, requirements)
66
+ old_method.bind(self).(name, requirements)
67
+ end
68
+
69
+ end
70
+ end
71
+ end
72
+
73
+
74
+ module Pod
75
+ class Installer
76
+
77
+ def prebuild_pod_targets
78
+
79
+ all = []
80
+ aggregate_targets = (self.aggregate_targets || []).select { |a| a.platform != :watchos }
81
+ aggregate_targets.each do |aggregate_target|
82
+ target_definition = aggregate_target.target_definition
83
+ targets = aggregate_target.pod_targets || []
84
+
85
+ UI.puts "🔍 Processing #{aggregate_target.name}:"
86
+ UI.puts "🔍 pod_targets count: #{targets.count}"
87
+
88
+ # filter prebuild
89
+ prebuild_names = target_definition.prebuild_framework_names
90
+ if not Podfile::DSL.prebuild_all
91
+ targets = targets.select { |pod_target| prebuild_names.include?(pod_target.pod_name) }
92
+ end
93
+ dependency_targets = targets.map {|t| t.recursive_dependent_targets }.flatten.uniq || []
94
+ targets = (targets + dependency_targets).uniq
95
+
96
+ # filter should not prebuild
97
+ explict_should_not_names = target_definition.should_not_prebuild_framework_names
98
+ targets = targets.reject { |pod_target| explict_should_not_names.include?(pod_target.pod_name) }
99
+
100
+ all += targets
101
+ end
102
+
103
+ all = all.reject {|pod_target| sandbox.local?(pod_target.pod_name) }
104
+ all.uniq
105
+ end
106
+
107
+ # the root names who needs prebuild, including dependency pods.
108
+ def prebuild_pod_names
109
+ @prebuild_pod_names ||= self.prebuild_pod_targets.map(&:pod_name)
110
+ end
111
+
112
+ # 强制重新计算 prebuild_pod_names(用于主安装阶段)
113
+ def refresh_prebuild_pod_names!
114
+ @prebuild_pod_names = nil
115
+ prebuild_pod_names
116
+ end
117
+
118
+ end
119
+ end
120
+
121
+
122
+
@@ -0,0 +1,53 @@
1
+ module Pod
2
+ class PrebuildSandbox < Sandbox
3
+
4
+ # [String] standard_sandbox_path
5
+ def self.from_standard_sanbox_path(path)
6
+ # 将预构建目录设置到项目根目录,而不是Pods目录旁边
7
+ # 这样可以避免在删除Pods目录时丢失预构建的框架
8
+ project_root = Pathname.new(path).realpath.parent
9
+ prebuild_sandbox_path = project_root + "_Prebuild"
10
+ UI.puts "prebuild_sandbox_path: #{prebuild_sandbox_path}"
11
+ self.new(prebuild_sandbox_path)
12
+ end
13
+
14
+ def self.from_standard_sandbox(sandbox)
15
+ self.from_standard_sanbox_path(sandbox.root)
16
+ end
17
+
18
+ def standard_sanbox_path
19
+ self.root
20
+ end
21
+
22
+ def generate_framework_path
23
+ self.root + "GeneratedFrameworks"
24
+ end
25
+
26
+ def framework_folder_path_for_pod_name(name)
27
+ self.generate_framework_path + name
28
+ end
29
+
30
+ def exsited_framework_names
31
+ return [] unless generate_framework_path.exist?
32
+ generate_framework_path.children().map do |framework_name|
33
+ if framework_name.directory?
34
+ if not framework_name.children.empty?
35
+ File.basename(framework_name)
36
+ else
37
+ nil
38
+ end
39
+ else
40
+ nil
41
+ end
42
+ end.reject(&:nil?)
43
+ end
44
+
45
+ def framework_existed?(root_name)
46
+ return false unless generate_framework_path.exist?
47
+ generate_framework_path.children().any? do |child|
48
+ child.basename.to_s == root_name
49
+ end
50
+ end
51
+
52
+ end
53
+ end
@@ -0,0 +1,49 @@
1
+
2
+ module Pod
3
+ class Prebuild
4
+
5
+ # Check the targets, for the current limitation of the plugin
6
+ #
7
+ # @param [Array<PodTarget>] prebuilt_targets
8
+ def self.check_one_pod_should_have_only_one_target(prebuilt_targets)
9
+
10
+ targets_have_different_platforms = prebuilt_targets.select {|t| t.pod_name != t.name }
11
+
12
+ if targets_have_different_platforms.count > 0
13
+ names = targets_have_different_platforms.map(&:pod_name)
14
+ raw_names = targets_have_different_platforms.map(&:name)
15
+ message = "Oops, you came across a limitation of cocoapods-binary-matchup.
16
+
17
+ The plugin requires that one pod should have ONLY ONE target in the 'Pod.xcodeproj'. There are mainly 2 situations \
18
+ causing this problem:
19
+
20
+ 1. One pod integrates in 2 or more different platforms' targets. e.g.
21
+ ```
22
+ target 'iphoneApp' do
23
+ pod 'A', :binary => true
24
+ end
25
+ target 'watchApp' do
26
+ pod 'A'
27
+ end
28
+ ```
29
+
30
+ 2. Use different subspecs in multiple targets. e.g.
31
+ ```
32
+ target 'iphoneApp' do
33
+ pod 'A/core'
34
+ pod 'A/network'
35
+ end
36
+ target 'iphoneAppTest' do
37
+ pod 'A/core'
38
+ end
39
+ ```
40
+
41
+ Related pods: #{names}, target names: #{raw_names}
42
+ "
43
+ raise Informative, message
44
+ end
45
+ end
46
+
47
+
48
+ end
49
+ end