cocoapods-binary-bel 0.5.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,347 @@
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
+ end
150
+
151
+ def delete_standard_sand_box_pod(standard_sanbox)
152
+ if lockfile
153
+ changes = lockfile.detect_changes_with_podfile(podfile)
154
+ need_update_pods = (changes[:added] + changes[:changed] + changes[:removed]).to_a
155
+
156
+ need_update_pods.each do |pod_name|
157
+ pod_path = Pathname.new(standard_sanbox.root.to_s + "/#{pod_name}")
158
+ Pod::UI.puts("删除 #{pod_path.to_s}") if config.verbose
159
+ pod_path.rmtree if pod_path.exist?
160
+ end
161
+ end
162
+ end
163
+
164
+ def delete_all_standard_sandbox_pod(standard_sanbox)
165
+ if lockfile
166
+ changes = lockfile.detect_changes_with_podfile(podfile)
167
+ need_update_pods = (changes[:added] + changes[:changed] + changes[:removed] + changes[:unchanged]).to_a
168
+
169
+ need_update_pods.each do |pod_name|
170
+ pod_path = Pathname.new(standard_sanbox.root.to_s + "/#{pod_name}")
171
+ Pod::UI.puts("删除 #{pod_path.to_s}") if config.verbose
172
+ pod_path.rmtree if pod_path.exist?
173
+ end
174
+ end
175
+ end
176
+
177
+
178
+ # Build the needed framework files
179
+ def prebuild_frameworks!(after_write_lock)
180
+ # build options
181
+ sandbox_path = sandbox.root
182
+ existed_framework_folder = sandbox.generate_framework_path
183
+ bitcode_enabled = Pod::Podfile::DSL.bitcode_enabled
184
+ targets = []
185
+
186
+ if local_manifest != nil
187
+
188
+ if after_write_lock
189
+ changes = post_update_pods_changes
190
+ elsif
191
+ changes = prebuild_pods_changes
192
+ end
193
+
194
+ added = changes.added
195
+ changed = changes.changed
196
+ unchanged = changes.unchanged
197
+ deleted = changes.deleted
198
+
199
+ existed_framework_folder.mkdir unless existed_framework_folder.exist?
200
+ exsited_framework_pod_names = sandbox.exsited_framework_pod_names
201
+
202
+ # additions
203
+ missing = unchanged.select do |pod_name|
204
+ not exsited_framework_pod_names.include?(pod_name)
205
+ end
206
+
207
+
208
+ root_names_to_update = (added + changed + missing)
209
+
210
+ # transform names to targets
211
+ cache = []
212
+ targets = root_names_to_update.map do |pod_name|
213
+ tars = Pod.fast_get_targets_for_pod_name(pod_name, self.pod_targets, cache)
214
+ if tars.nil? || tars.empty?
215
+ raise "There's no target named (#{pod_name}) in Pod.xcodeproj.\n #{self.pod_targets.map(&:name)}" if t.nil?
216
+ end
217
+ tars
218
+ end.flatten
219
+
220
+ # add the dendencies
221
+ # dependency_targets = targets.map {|t| t.recursive_dependent_targets }.flatten.uniq || []
222
+ # targets = (targets + dependency_targets).uniq
223
+ else
224
+ targets = self.pod_targets
225
+ end
226
+
227
+ targets = targets.reject {|pod_target| sandbox.local?(pod_target.pod_name) }
228
+
229
+
230
+ # build!
231
+ Pod::UI.puts "Prebuild frameworks (total #{targets.count})"
232
+ Pod::Prebuild.remove_build_dir(sandbox_path)
233
+ targets.each do |target|
234
+ if !target.should_build?
235
+ UI.puts "Prebuilding #{target.label}"
236
+ next
237
+ end
238
+
239
+ output_path = sandbox.framework_folder_path_for_target_name(target.name)
240
+ output_path.rmtree if output_path.exist?
241
+ output_path.mkpath unless output_path.exist?
242
+ Pod::Prebuild.build(sandbox_path, target, output_path, bitcode_enabled, Podfile::DSL.custom_build_options, Podfile::DSL.custom_build_options_simulator)
243
+
244
+ # save the resource paths for later installing
245
+ if target.static_framework? and !target.resource_paths.empty?
246
+ framework_path = output_path + target.framework_name
247
+ standard_sandbox_path = sandbox.standard_sanbox_path
248
+
249
+ resources = begin
250
+ if Pod::VERSION.start_with? "1.5"
251
+ target.resource_paths
252
+ else
253
+ # resource_paths is Hash{String=>Array<String>} on 1.6 and above
254
+ # (use AFNetworking to generate a demo data)
255
+ # https://github.com/leavez/cocoapods-binary/issues/50
256
+ target.resource_paths.values.flatten
257
+ end
258
+ end
259
+ raise "Wrong type: #{resources}" unless resources.kind_of? Array
260
+
261
+ path_objects = resources.map do |path|
262
+ object = Prebuild::Passer::ResourcePath.new
263
+ object.real_file_path = framework_path + File.basename(path)
264
+ object.target_file_path = path.gsub('${PODS_ROOT}', standard_sandbox_path.to_s) if path.start_with? '${PODS_ROOT}'
265
+ object.target_file_path = path.gsub("${PODS_CONFIGURATION_BUILD_DIR}", standard_sandbox_path.to_s) if path.start_with? "${PODS_CONFIGURATION_BUILD_DIR}"
266
+ object
267
+ end
268
+ Prebuild::Passer.resources_to_copy_for_static_framework[target.name] = path_objects
269
+ end
270
+
271
+ end
272
+ Pod::Prebuild.remove_build_dir(sandbox_path)
273
+
274
+
275
+ # copy vendored libraries and frameworks
276
+ targets.each do |target|
277
+ root_path = self.sandbox.pod_dir(target.name)
278
+ target_folder = sandbox.framework_folder_path_for_target_name(target.name)
279
+
280
+ # If target shouldn't build, we copy all the original files
281
+ # This is for target with only .a and .h files
282
+ if not target.should_build?
283
+ Prebuild::Passer.target_names_to_skip_integration_framework << target.name
284
+ FileUtils.cp_r(root_path, target_folder, :remove_destination => true)
285
+ next
286
+ end
287
+
288
+ target.spec_consumers.each do |consumer|
289
+ file_accessor = Sandbox::FileAccessor.new(root_path, consumer)
290
+ lib_paths = file_accessor.vendored_frameworks || []
291
+ lib_paths += file_accessor.vendored_libraries
292
+ # @TODO dSYM files
293
+ lib_paths.each do |lib_path|
294
+ relative = lib_path.relative_path_from(root_path)
295
+ destination = target_folder + relative
296
+ destination.dirname.mkpath unless destination.dirname.exist?
297
+ FileUtils.cp_r(lib_path, destination, :remove_destination => true)
298
+ end
299
+ end
300
+ end
301
+
302
+ # save the pod_name for prebuild framwork in sandbox
303
+ targets.each do |target|
304
+ sandbox.save_pod_name_for_target target
305
+ end
306
+
307
+ # Remove useless files
308
+ # remove useless pods
309
+ all_needed_names = self.pod_targets.map(&:name).uniq
310
+ useless_target_names = sandbox.exsited_framework_target_names.reject do |name|
311
+ all_needed_names.include? name
312
+ end
313
+ # 不删除已经编译好的framework
314
+ # useless_target_names.each do |name|
315
+ # path = sandbox.framework_folder_path_for_target_name(name)
316
+ # path.rmtree if path.exist?
317
+ # end
318
+
319
+ if not Podfile::DSL.dont_remove_source_code
320
+ # only keep manifest.lock and framework folder in _Prebuild
321
+ to_remain_files = ["Manifest.lock", File.basename(existed_framework_folder)]
322
+ to_delete_files = sandbox_path.children.select do |file|
323
+ filename = File.basename(file)
324
+ not to_remain_files.include?(filename)
325
+ end
326
+ to_delete_files.each do |path|
327
+ path.rmtree if path.exist?
328
+ end
329
+ else
330
+ # just remove the tmp files
331
+ path = sandbox.root + 'Manifest.lock.tmp'
332
+ path.rmtree if path.exist?
333
+ end
334
+ end
335
+
336
+ # patch the post install hook
337
+ old_method2 = instance_method(:run_plugins_post_install_hooks)
338
+ define_method(:run_plugins_post_install_hooks) do
339
+ old_method2.bind(self).()
340
+ if Pod::is_prebuild_stage
341
+ self.prebuild_frameworks!(true)
342
+ end
343
+ end
344
+
345
+
346
+ end
347
+ end
@@ -0,0 +1,28 @@
1
+ module Pod
2
+ class Command
3
+ class Install < Command
4
+ @@use_source = false
5
+ def self.options
6
+ [
7
+ ['--hsource', 'from cocoapods-binary-bel, all frameworks use source code'],
8
+ ].concat(super).reject { |(name, _)| name == '--no-repo-update' }
9
+ end
10
+
11
+ def initialize(argv)
12
+ super
13
+ @@use_source = argv.flag?('hsource', false)
14
+ end
15
+
16
+ def self.all_use_source
17
+ @@use_source
18
+ end
19
+
20
+ def self.run(argv)
21
+ super(argv)
22
+ end
23
+
24
+
25
+ end
26
+ end
27
+ end
28
+
@@ -0,0 +1,3 @@
1
+ module CocoapodsBinaryBel
2
+ VERSION = "0.5.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