cocoapods-binary-bel 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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