cocoapods-binary-bugfix 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.
@@ -0,0 +1,370 @@
1
+ require_relative 'rome/build_framework'
2
+ require_relative 'helper/passer'
3
+ require_relative 'helper/target_checker'
4
+ require 'cfpropertylist'
5
+
6
+
7
+
8
+
9
+ # patch prebuild ability
10
+ module Pod
11
+ class Installer
12
+
13
+ include Config::Mixin
14
+
15
+ private
16
+
17
+ def local_manifest
18
+ if not @local_manifest_inited
19
+ @local_manifest_inited = true
20
+ raise "This method should be call before generate project" unless self.analysis_result == nil
21
+ @local_manifest = self.sandbox.manifest
22
+ end
23
+ @local_manifest
24
+ end
25
+ # @return [Analyzer::SpecsState]
26
+ def prebuild_pods_changes
27
+ local_manifest = self.sandbox.manifest
28
+ return nil if local_manifest.nil?
29
+ # if @prebuild_pods_changes.nil?
30
+ changes = local_manifest.detect_changes_with_podfile(podfile)
31
+ unchanged_pod_names = changes[:unchanged]
32
+ changed_pod_names = changes[:changed]
33
+ unchanged_pod_names.reverse_each do |name|
34
+ mainfest_pod_version = local_manifest.version(name).to_s
35
+ already_prebuild_version = prebuilded_framework_version(name) || "未找到"
36
+ if not compare_version(mainfest_pod_version, already_prebuild_version)
37
+ Pod::UI.puts("- #{name} 已编译版本 #{already_prebuild_version}, manifest中的版本: #{mainfest_pod_version}") if config.verbose
38
+ changed_pod_names = changed_pod_names.push(name)
39
+ unchanged_pod_names.delete(name)
40
+ end
41
+ end
42
+
43
+ changes[:changed] = changed_pod_names
44
+ changes[:unchanged] = unchanged_pod_names
45
+ Pod::UI.puts("Pre 需要重编译的framework : #{changed_pod_names.to_s}") if config.verbose
46
+ @prebuild_pods_changes = Analyzer::SpecsState.new(changes)
47
+ # save the chagnes info for later stage
48
+ Pod::Prebuild::Passer.prebuild_pods_changes = @prebuild_pods_changes
49
+ @prebuild_pods_changes
50
+ end
51
+
52
+ # compare version
53
+ # 1.2.0 == 1.2 => true
54
+ # 1.2.1 != 1.2.0 => false
55
+ def compare_version(first_version, second_version)
56
+ first_nums = first_version.split('.')
57
+ second_nums = second_version.split('.')
58
+
59
+ first_nums.pop until first_nums.last.to_i != 0
60
+ second_nums.pop until second_nums.last.to_i != 0
61
+
62
+ first_nums == second_nums
63
+ end
64
+
65
+
66
+ public
67
+
68
+ # pod update 之后 lockfile 文件更新,更新lockfile对象,再次检查与预编译的版本是否一致
69
+ def post_update_pods_changes
70
+ changes = lockfile.detect_changes_with_podfile(podfile)
71
+ unchanged_pod_names = changes[:unchanged]
72
+ changed_pod_names = changes[:changed]
73
+ add_pod_names = changes[:added]
74
+ removed_pod_names = changes[:removed]
75
+
76
+
77
+ unchanged_pod_names.reverse_each do |name|
78
+ mainfest_pod_version = lockfile.version(name).to_s
79
+ already_prebuild_version = prebuilded_framework_version(name) || "未找到"
80
+ if compare_version(mainfest_pod_version, already_prebuild_version)
81
+ # 已经编译了
82
+ removed_pod_names.delete(name) if removed_pod_names.include?(name)
83
+ add_pod_names.delete(name) if add_pod_names.include?(name)
84
+ changed_pod_names.delete(name) if changed_pod_names.include?(name)
85
+
86
+ else
87
+ # 未找到相对应的版本
88
+ if already_prebuild_version == "99999.99999.99999"
89
+ Pod::UI.puts("- #{name}: 未找到预编译文件, manifest中的版本: #{mainfest_pod_version}") if config.verbose
90
+ else
91
+ Pod::UI.puts("- #{name}: 已编译版 #{already_prebuild_version}, manifest中的版本: #{mainfest_pod_version}") if config.verbose
92
+ end
93
+ changed_pod_names = changed_pod_names.push(name)
94
+ unchanged_pod_names.delete(name) if unchanged_pod_names.include?(name)
95
+ end
96
+ end
97
+ changes[:removed] = removed_pod_names
98
+ changes[:added] = add_pod_names
99
+ changes[:changed] = changed_pod_names
100
+ changes[:unchanged] = unchanged_pod_names
101
+ Pod::UI.puts("post 需要重编译的framework : #{(changed_pod_names + removed_pod_names + add_pod_names ).to_a}") if config.verbose
102
+ @prebuild_pods_changes = Analyzer::SpecsState.new(changes)
103
+ # save the chagnes info for later stage
104
+ Pod::Prebuild::Passer.prebuild_pods_changes = @prebuild_pods_changes
105
+ @prebuild_pods_changes
106
+
107
+ end
108
+
109
+ # check if need to prebuild
110
+ def have_exact_prebuild_cache?
111
+
112
+ # check if need build frameworks
113
+ return false if local_manifest == nil
114
+
115
+ changes = prebuild_pods_changes
116
+ added = changes.added
117
+ changed = changes.changed
118
+ unchanged = changes.unchanged
119
+ deleted = changes.deleted
120
+
121
+ exsited_framework_pod_names = sandbox.exsited_framework_pod_names
122
+ missing = unchanged.select do |pod_name|
123
+ not exsited_framework_pod_names.include?(pod_name)
124
+ end
125
+
126
+ needed = (added + changed + deleted + missing)
127
+
128
+ return needed.empty?
129
+ end
130
+ # 当前已编译的framework的版本
131
+ def prebuilded_framework_version(name)
132
+ path = self.sandbox.plist_path_for_target_name(name)
133
+ framework_version = "99999.99999.99999"
134
+ if Pathname.new(path).exist?
135
+ plist_file = CFPropertyList::List.new(:file => path)
136
+ data = CFPropertyList.native_types(plist_file.value)
137
+ framework_version = data["CFBundleShortVersionString"]
138
+ end
139
+ framework_version
140
+ end
141
+
142
+
143
+ # The install method when have completed cache
144
+ def install_when_cache_hit!
145
+ # just print log
146
+ self.sandbox.exsited_framework_target_names.each do |name|
147
+ UI.puts "Using #{name}" if config.verbose
148
+ end
149
+
150
+ self.sandbox
151
+ #处理静态库resources 资源文件
152
+ self.resolve_dependencies
153
+ self.download_dependencies
154
+
155
+ self.handle_static_framework_resouces
156
+
157
+ end
158
+
159
+ def delete_standard_sand_box_pod(standard_sanbox)
160
+ if lockfile
161
+ changes = lockfile.detect_changes_with_podfile(podfile)
162
+ need_update_pods = (changes[:added] + changes[:changed] + changes[:removed]).to_a
163
+
164
+ need_update_pods.each do |pod_name|
165
+ pod_path = Pathname.new(standard_sanbox.root.to_s + "/#{pod_name}")
166
+ Pod::UI.puts("删除 #{pod_path.to_s}") if config.verbose
167
+ pod_path.rmtree if pod_path.exist?
168
+ end
169
+ end
170
+ end
171
+
172
+ def delete_all_standard_sandbox_pod(standard_sanbox)
173
+ if lockfile
174
+ changes = lockfile.detect_changes_with_podfile(podfile)
175
+ need_update_pods = (changes[:added] + changes[:changed] + changes[:removed] + changes[:unchanged]).to_a
176
+
177
+ need_update_pods.each do |pod_name|
178
+ pod_path = Pathname.new(standard_sanbox.root.to_s + "/#{pod_name}")
179
+ Pod::UI.puts("删除 #{pod_path.to_s}") if config.verbose
180
+ pod_path.rmtree if pod_path.exist?
181
+ end
182
+ end
183
+ end
184
+ # 处理静态库资源
185
+ def handle_static_framework_resouces
186
+ all_static_framework_targets = pod_targets.reject{|pod_target| not pod_target.static_framework? or pod_target.resource_paths.empty? }
187
+ all_static_framework_targets.each do |target|
188
+ output_path = sandbox.framework_folder_path_for_target_name(target.name)
189
+ if target.static_framework? and !target.resource_paths.empty?
190
+ framework_path = output_path + target.framework_name
191
+ standard_sandbox_path = sandbox.standard_sanbox_path
192
+ resources = begin
193
+ if Pod::VERSION.start_with? "1.5"
194
+ target.resource_paths
195
+ else
196
+ # resource_paths is Hash{String=>Array<String>} on 1.6 and above
197
+ # (use AFNetworking to generate a demo data)
198
+ # https://github.com/leavez/cocoapods-binary/issues/50
199
+ target.resource_paths.values.flatten
200
+ end
201
+ end
202
+ raise "Wrong type: #{resources}" unless resources.kind_of? Array
203
+
204
+ path_objects = resources.map do |path|
205
+ prebuild_real_path = (path.gsub('${PODS_ROOT}', sandbox.root.to_s) if path.start_with? '${PODS_ROOT}')|| ""
206
+ real_file_path = framework_path + File.basename(path)
207
+ if Pathname.new(prebuild_real_path).exist? and
208
+ Pathname.new(framework_path).exist? and
209
+ not Pathname.new(real_file_path).exist?
210
+ # 静态库的resource,拷贝至framework目录下
211
+ FileUtils.cp_r(prebuild_real_path, real_file_path, :remove_destination => true)
212
+ end
213
+ object = Prebuild::Passer::ResourcePath.new
214
+ object.real_file_path = real_file_path
215
+ object.target_file_path = path.gsub('${PODS_ROOT}', standard_sandbox_path.to_s) if path.start_with? '${PODS_ROOT}'
216
+ object.target_file_path = path.gsub("${PODS_CONFIGURATION_BUILD_DIR}", standard_sandbox_path.to_s) if path.start_with? "${PODS_CONFIGURATION_BUILD_DIR}"
217
+ object
218
+ end
219
+ Prebuild::Passer.resources_to_copy_for_static_framework[target.name] = path_objects
220
+ end
221
+ end
222
+ end
223
+
224
+
225
+ # Build the needed framework files
226
+ def prebuild_frameworks!(after_write_lock)
227
+ # build options
228
+ sandbox_path = sandbox.root
229
+ existed_framework_folder = sandbox.generate_framework_path
230
+ bitcode_enabled = Pod::Podfile::DSL.bitcode_enabled
231
+ targets = []
232
+
233
+ if local_manifest != nil
234
+
235
+ if after_write_lock
236
+ changes = post_update_pods_changes
237
+ elsif
238
+ changes = prebuild_pods_changes
239
+ end
240
+
241
+ added = changes.added
242
+ changed = changes.changed
243
+ unchanged = changes.unchanged
244
+ deleted = changes.deleted
245
+
246
+ existed_framework_folder.mkdir unless existed_framework_folder.exist?
247
+ exsited_framework_pod_names = sandbox.exsited_framework_pod_names
248
+
249
+ # additions
250
+ missing = unchanged.select do |pod_name|
251
+ not exsited_framework_pod_names.include?(pod_name)
252
+ end
253
+
254
+
255
+ root_names_to_update = (added + changed + missing)
256
+
257
+ # transform names to targets
258
+ cache = []
259
+ targets = root_names_to_update.map do |pod_name|
260
+ tars = Pod.fast_get_targets_for_pod_name(pod_name, self.pod_targets, cache)
261
+ if tars.nil? || tars.empty?
262
+ raise "There's no target named (#{pod_name}) in Pod.xcodeproj.\n #{self.pod_targets.map(&:name)}" if t.nil?
263
+ end
264
+ tars
265
+ end.flatten
266
+
267
+ # add the dendencies
268
+ # dependency_targets = targets.map {|t| t.recursive_dependent_targets }.flatten.uniq || []
269
+ # targets = (targets + dependency_targets).uniq
270
+ else
271
+ targets = self.pod_targets
272
+ end
273
+
274
+ targets = targets.reject {|pod_target| sandbox.local?(pod_target.pod_name) }
275
+
276
+ # build!
277
+ Pod::UI.puts "Prebuild frameworks (total #{targets.count})"
278
+ Pod::Prebuild.remove_build_dir(sandbox_path)
279
+ targets.each do |target|
280
+ if !target.should_build?
281
+ UI.puts "Prebuilding #{target.label}"
282
+ next
283
+ end
284
+
285
+ output_path = sandbox.framework_folder_path_for_target_name(target.name)
286
+ output_path.rmtree if output_path.exist?
287
+ output_path.mkpath unless output_path.exist?
288
+ Pod::Prebuild.build(sandbox_path, target, output_path, bitcode_enabled, Podfile::DSL.custom_build_options, Podfile::DSL.custom_build_options_simulator)
289
+ end
290
+ # check static_framework resources
291
+ self.handle_static_framework_resouces
292
+ Pod::Prebuild.remove_build_dir(sandbox_path)
293
+
294
+
295
+
296
+
297
+ # copy vendored libraries and frameworks
298
+ targets.each do |target|
299
+ root_path = self.sandbox.pod_dir(target.name)
300
+ target_folder = sandbox.framework_folder_path_for_target_name(target.name)
301
+
302
+ # If target shouldn't build, we copy all the original files
303
+ # This is for target with only .a and .h files
304
+ if not target.should_build?
305
+ Prebuild::Passer.target_names_to_skip_integration_framework << target.name
306
+ FileUtils.cp_r(root_path, target_folder, :remove_destination => true)
307
+ next
308
+ end
309
+
310
+ target.spec_consumers.each do |consumer|
311
+ file_accessor = Sandbox::FileAccessor.new(root_path, consumer)
312
+ lib_paths = file_accessor.vendored_frameworks || []
313
+ lib_paths += file_accessor.vendored_libraries
314
+ # @TODO dSYM files
315
+ lib_paths.each do |lib_path|
316
+ relative = lib_path.relative_path_from(root_path)
317
+ destination = target_folder + relative
318
+ destination.dirname.mkpath unless destination.dirname.exist?
319
+ FileUtils.cp_r(lib_path, destination, :remove_destination => true)
320
+ end
321
+ end
322
+ end
323
+
324
+ # save the pod_name for prebuild framwork in sandbox
325
+ targets.each do |target|
326
+ sandbox.save_pod_name_for_target target
327
+ end
328
+
329
+ # Remove useless files
330
+ # remove useless pods
331
+ all_needed_names = self.pod_targets.map(&:name).uniq
332
+ useless_target_names = sandbox.exsited_framework_target_names.reject do |name|
333
+ all_needed_names.include? name
334
+ end
335
+ # 不删除已经编译好的framework
336
+ # useless_target_names.each do |name|
337
+ # path = sandbox.framework_folder_path_for_target_name(name)
338
+ # path.rmtree if path.exist?
339
+ # end
340
+
341
+ if not Podfile::DSL.dont_remove_source_code
342
+ # only keep manifest.lock and framework folder in _Prebuild
343
+ to_remain_files = ["Manifest.lock", File.basename(existed_framework_folder)]
344
+ to_delete_files = sandbox_path.children.select do |file|
345
+ filename = File.basename(file)
346
+ not to_remain_files.include?(filename)
347
+ end
348
+
349
+ to_delete_files.each do |path|
350
+ path.rmtree if path.exist?
351
+ end
352
+ else
353
+ # just remove the tmp files
354
+ path = sandbox.root + 'Manifest.lock.tmp'
355
+ path.rmtree if path.exist?
356
+ end
357
+ end
358
+
359
+ # patch the post install hook
360
+ old_method2 = instance_method(:run_plugins_post_install_hooks)
361
+ define_method(:run_plugins_post_install_hooks) do
362
+ old_method2.bind(self).()
363
+ if Pod::is_prebuild_stage
364
+ self.prebuild_frameworks!(true)
365
+ end
366
+ end
367
+
368
+
369
+ end
370
+ end
@@ -0,0 +1,51 @@
1
+ module Pod
2
+ class Command
3
+ class Install < Command
4
+ @@use_source = false
5
+
6
+ class << self
7
+ alias :original_options :options
8
+ end
9
+ def self.options
10
+ [['--hsource', 'from cocoapods-binaryhqp, all frameworks use source code']].concat(original_options)
11
+ end
12
+
13
+ alias :original_initialize :initialize
14
+ def initialize(argv)
15
+ @@use_source = argv.flag?('hsource', false)
16
+ original_initialize(argv)
17
+ end
18
+
19
+ def self.all_use_source
20
+ @@use_source
21
+ end
22
+
23
+ def self.set_all_use_source(use)
24
+ @@use_source = use
25
+ end
26
+
27
+
28
+ end
29
+ end
30
+ end
31
+
32
+ module Pod
33
+ class Command
34
+ class Update < Command
35
+ class << self
36
+ alias :original_options :options
37
+ end
38
+ def self.options
39
+ [['--hsource', 'from cocoapods-binaryhqp, all frameworks use source code']].concat(original_options)
40
+ end
41
+
42
+ alias :original_initialize :initialize
43
+ def initialize(argv)
44
+ use = argv.flag?('hsource', false)
45
+ Pod::Command::Install.set_all_use_source(use)
46
+ original_initialize(argv)
47
+ end
48
+ end
49
+ end
50
+ end
51
+
@@ -0,0 +1,3 @@
1
+ module CocoapodsBinaryBugfix
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,101 @@
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
+ old_method = instance_method(:pod)
23
+
24
+ define_method(:pod) do |name, *args|
25
+ if !@@enable_prebuild_patch
26
+ old_method.bind(self).(name, *args)
27
+ return
28
+ end
29
+
30
+ # patched content
31
+ should_prebuild = Pod::Podfile::DSL.prebuild_all || (not Pod::Podfile::DSL.framework_source_all)
32
+ local = false
33
+
34
+ options = args.last
35
+ if options.is_a?(Hash) and options[Pod::Prebuild.keyword] != nil
36
+ should_prebuild = options[Pod::Prebuild.keyword] && (not Pod::Podfile::DSL.framework_source_all)
37
+ local = (options[:path] != nil)
38
+ end
39
+
40
+ if Pod::Command::Install.all_use_source
41
+ should_prebuild = false
42
+ end
43
+
44
+ if should_prebuild and (not local)
45
+ old_method.bind(self).(name, *args)
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+
52
+ # a force disable option for integral
53
+ class Installer
54
+ def self.force_disable_integration(value)
55
+ @@force_disable_integration = value
56
+ end
57
+
58
+ old_method = instance_method(:integrate_user_project)
59
+ define_method(:integrate_user_project) do
60
+ if @@force_disable_integration
61
+ return
62
+ end
63
+ old_method.bind(self).()
64
+ end
65
+ end
66
+
67
+ # a option to disable install complete message
68
+ class Installer
69
+ def self.disable_install_complete_message(value)
70
+ @@disable_install_complete_message = value
71
+ end
72
+
73
+ old_method = instance_method(:print_post_install_message)
74
+ define_method(:print_post_install_message) do
75
+ if @@disable_install_complete_message
76
+ return
77
+ end
78
+ old_method.bind(self).()
79
+ end
80
+ end
81
+
82
+ # option to disable write lockfiles
83
+ class Config
84
+
85
+ @@force_disable_write_lockfile = false
86
+ def self.force_disable_write_lockfile(value)
87
+ @@force_disable_write_lockfile = value
88
+ end
89
+
90
+ old_method = instance_method(:lockfile_path)
91
+ define_method(:lockfile_path) do
92
+ if @@force_disable_write_lockfile
93
+ # As config is a singleton, sandbox_root refer to the standard sandbox.
94
+ return PrebuildSandbox.from_standard_sanbox_path(sandbox_root).root + 'Manifest.lock.tmp'
95
+ else
96
+ return old_method.bind(self).()
97
+ end
98
+ end
99
+ end
100
+
101
+ end
@@ -0,0 +1,78 @@
1
+ # ABOUT NAMES
2
+ #
3
+ # There are many kinds of name in cocoapods. Two main names are widely used in this plugin.
4
+ # - root_spec.name (spec.root_name, targe.pod_name):
5
+ # aka "pod_name"
6
+ # the name we use in podfile. the concept.
7
+ #
8
+ # - target.name:
9
+ # aka "target_name"
10
+ # the name of the final target in xcode project. the final real thing.
11
+ #
12
+ # One pod may have multiple targets in xcode project, due to one pod can be used in mutiple
13
+ # platform simultaneously. So one `root_spec.name` may have multiple coresponding `target.name`s.
14
+ # Therefore, map a spec to/from targets is a little complecated. It's one to many.
15
+ #
16
+
17
+ # Tool to transform Pod_name to target efficiently
18
+ module Pod
19
+ def self.fast_get_targets_for_pod_name(pod_name, targets, cache)
20
+ pod_name_to_targets_hash = nil
21
+ if cache.empty?
22
+ pod_name_to_targets_hash = targets.reduce({}) do |sum, target|
23
+ array = sum[target.pod_name] || []
24
+ array << target
25
+ sum[target.pod_name] = array
26
+ sum
27
+ end
28
+ cache << pod_name_to_targets_hash
29
+ else
30
+ pod_name_to_targets_hash = cache.first
31
+ end
32
+
33
+ pod_name_to_targets_hash[pod_name] || []
34
+ end
35
+ end
36
+
37
+
38
+
39
+
40
+
41
+
42
+ # Target:
43
+
44
+ # def pod_name
45
+ # root_spec.name
46
+ # end
47
+
48
+ # def name
49
+ # pod_name + #{scope_suffix}
50
+ # end
51
+
52
+ # def product_module_name
53
+ # root_spec.module_name
54
+ # end
55
+
56
+ # def framework_name
57
+ # "#{product_module_name}.framework"
58
+ # end
59
+
60
+ # def product_name
61
+ # if requires_frameworks?
62
+ # framework_name
63
+ # else
64
+ # static_library_name
65
+ # end
66
+ # end
67
+
68
+ # def product_basename
69
+ # if requires_frameworks?
70
+ # product_module_name
71
+ # else
72
+ # label
73
+ # end
74
+ # end
75
+
76
+ # def framework_name
77
+ # "#{product_module_name}.framework"
78
+ # 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