cocoapods-xlbuild 1.0.0

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 5748f33f7f849025871d30147a549cc44e663050f0db5f4d566e704a79b5a8af
4
+ data.tar.gz: 8fdda2558312a18ce1428d9012e8c137ed7740dd015108103369ab62ed3615b1
5
+ SHA512:
6
+ metadata.gz: de501a7958a4dd3fd69c1d594a5635ab71b3a08e1827b308e33e290740c7860ec5efdf301c95a492e54be686e7bf4c8dc3f588c7088d1d6881bb49dc12b4b1bc
7
+ data.tar.gz: e649985d9a764cff3fcb0a3b305cffa4fba37b73e228d0c431ac48be3b761ff3661289d703a89460c9f2a8ee3b29aa1734a378cda68879d463d6c338a6ad7f62
@@ -0,0 +1,377 @@
1
+ require_relative 'helper/podfile_options'
2
+ require_relative 'helper/feature_switches'
3
+ require_relative 'helper/prebuild_sandbox'
4
+ require_relative 'helper/passer'
5
+ require_relative 'helper/names'
6
+ require_relative 'helper/target_checker'
7
+
8
+
9
+ # NOTE:
10
+ # This file will only be loaded on normal pod install step
11
+ # so there's no need to check is_prebuild_stage
12
+
13
+
14
+
15
+ # Provide a special "download" process for prebuilded pods.
16
+ #
17
+ # As the frameworks is already exsited in local folder. We
18
+ # just create a symlink to the original target folder.
19
+ #
20
+ module Pod
21
+ class Installer
22
+ class PodSourceInstaller
23
+
24
+ def install_for_prebuild!(standard_sanbox)
25
+ return if standard_sanbox.local? self.name
26
+
27
+ # make a symlink to target folder
28
+ prebuild_sandbox = Pod::PrebuildSandbox.from_standard_sandbox(standard_sanbox)
29
+ # if spec used in multiple platforms, it may return multiple paths
30
+ target_names = prebuild_sandbox.existed_target_names_for_pod_name(self.name)
31
+
32
+ def walk(path, &action)
33
+ return unless path.exist?
34
+ path.children.each do |child|
35
+ result = action.call(child, &action)
36
+ if child.directory?
37
+ walk(child, &action) if result
38
+ end
39
+ end
40
+ end
41
+
42
+ def make_link(source, target, uselink)
43
+ source = Pathname.new(source)
44
+ target = Pathname.new(target)
45
+ target.parent.mkpath unless target.parent.exist?
46
+ relative_source = source.relative_path_from(target.parent)
47
+ if uselink
48
+ FileUtils.ln_sf(relative_source, target)
49
+ else
50
+ if File.directory?(source)
51
+ FileUtils.cp_r source, target, :remove_destination => true
52
+ else
53
+ FileUtils.cp source, target
54
+ end
55
+ if not target.exist?
56
+ raise "资源导入失败:#{target}"
57
+ end
58
+ end
59
+ end
60
+
61
+ def mirror_with_symlink(source, basefolder, target_folder, uselink)
62
+ target = target_folder + source.relative_path_from(basefolder)
63
+ make_link(source, target, uselink)
64
+ end
65
+
66
+ target_names.each do |name|
67
+ # symbol link copy all substructure
68
+ real_file_folder = prebuild_sandbox.framework_folder_path_for_target_name(name)
69
+
70
+ # If have only one platform, just place int the root folder of this pod.
71
+ # If have multiple paths, we use a sperated folder to store different
72
+ # platform frameworks. e.g. AFNetworking/AFNetworking-iOS/AFNetworking.framework
73
+
74
+ target_folder = standard_sanbox.pod_dir(self.name)
75
+ if target_names.count > 1
76
+ target_folder += real_file_folder.basename
77
+ end
78
+ target_folder.rmtree if target_folder.exist?
79
+ target_folder.mkpath
80
+
81
+ walk(real_file_folder) do |child|
82
+ source = child
83
+
84
+ # only make symlink to file and `.framework` folder
85
+ if child.directory?
86
+ if [".framework"].include? child.extname
87
+ mirror_with_symlink(source, real_file_folder, target_folder, true)
88
+ next false # return false means don't go deeper
89
+ elsif [".dSYM"].include? child.extname
90
+ mirror_with_symlink(source, real_file_folder, target_folder, false)
91
+ next false # return false means don't go deeper
92
+ elsif [".bundle"].include? child.extname
93
+ mirror_with_symlink(source, real_file_folder, target_folder, false)
94
+ next false
95
+ else
96
+ next true
97
+ end
98
+ elsif child.file?
99
+ mirror_with_symlink(source, real_file_folder, target_folder, false)
100
+ next true
101
+ else
102
+ next true
103
+ end
104
+ end
105
+
106
+
107
+ # symbol link copy resource for static framework
108
+ hash = Prebuild::Passer.resources_to_copy_for_static_framework || {}
109
+ path_objects = hash[name]
110
+ if path_objects != nil
111
+ path_objects.each do |object|
112
+ if object.real_file_path != nil
113
+ real_path = Pathname.new(object.target_file_path)
114
+ real_path.rmtree if real_path.exist?
115
+ make_link(object.real_file_path, object.target_file_path, false)
116
+ end
117
+ end
118
+ end
119
+ end # of for each
120
+
121
+ end # of method
122
+
123
+ end
124
+ end
125
+ end
126
+
127
+
128
+ # Let cocoapods use the prebuild framework files in install process.
129
+ #
130
+ # the code only effect the second pod install process.
131
+ #
132
+ module Pod
133
+ class Installer
134
+
135
+
136
+ # Remove the old target files if prebuild frameworks changed
137
+ def remove_target_files_if_needed
138
+
139
+ changes = Pod::Prebuild::Passer.prebuild_pod_targets_changes
140
+ updated_names = []
141
+ if changes == nil
142
+ updated_names = PrebuildSandbox.from_standard_sandbox(self.sandbox).exsited_framework_pod_names
143
+ else
144
+ t_changes = Pod::Prebuild::Passer.prebuild_pods_changes
145
+ added = t_changes.added
146
+ changed = t_changes.changed
147
+ deleted = t_changes.deleted
148
+ updated_names = (added + changed + deleted).to_a
149
+
150
+ updated_names = (changes + updated_names).uniq
151
+ end
152
+
153
+ updated_names.each do |name|
154
+ root_name = Specification.root_name(name)
155
+ next if self.sandbox.local?(root_name)
156
+
157
+ # delete the cached files
158
+ target_path = self.sandbox.pod_dir(root_name)
159
+ target_path.rmtree if target_path.exist?
160
+
161
+ support_path = sandbox.target_support_files_dir(root_name)
162
+ support_path.rmtree if support_path.exist?
163
+ end
164
+
165
+ end
166
+
167
+ def save_change_targets!
168
+ sandbox_path = sandbox.root
169
+ existed_framework_folder = sandbox.generate_framework_path
170
+ if local_manifest != nil
171
+ changes = prebuild_pods_changes
172
+ added = changes.added
173
+ changed = changes.changed
174
+ unchanged = changes.unchanged
175
+ deleted = changes.deleted.to_a
176
+
177
+ existed_framework_folder.mkdir unless existed_framework_folder.exist?
178
+ exsited_framework_pod_names = sandbox.exsited_framework_pod_names
179
+
180
+ # additions
181
+ missing = unchanged.select do |pod_name|
182
+ not exsited_framework_pod_names.include?(pod_name)
183
+ end
184
+
185
+ # 保存有改变的target列表
186
+ root_names_to_update = (added + changed + missing).uniq
187
+ updates_target_names = (root_names_to_update + deleted).uniq
188
+ cache = []
189
+ updates_targets = []
190
+ updates_target_names.each do |pod_name|
191
+ tars = Pod.fast_get_targets_for_pod_name(pod_name, self.pod_targets, cache)
192
+ if tars.nil?
193
+ tars = []
194
+ end
195
+ updates_targets = (updates_targets + tars).uniq
196
+ end
197
+ updates_dependency_targets = updates_targets.map {|t|
198
+ t.recursive_dependent_targets
199
+ }.flatten.uniq || []
200
+ dependency_names = updates_dependency_targets.map { |e| e.pod_name }
201
+ if Pod::Prebuild::Passer.prebuild_pod_targets_changes.nil?
202
+ Pod::Prebuild::Passer.prebuild_pod_targets_changes = (updates_target_names + dependency_names).uniq
203
+ else
204
+ Pod::Prebuild::Passer.prebuild_pod_targets_changes = (Pod::Prebuild::Passer.prebuild_pod_targets_changes + updates_target_names + dependency_names).uniq
205
+ end
206
+ end
207
+ end
208
+
209
+ # Modify specification to use only the prebuild framework after analyzing
210
+ old_method2 = instance_method(:resolve_dependencies)
211
+ define_method(:resolve_dependencies) do
212
+ if Pod::is_prebuild_stage
213
+ # call original
214
+ old_method2.bind(self).()
215
+ self.save_change_targets!
216
+ else
217
+ # Remove the old target files, else it will not notice file changes
218
+ self.remove_target_files_if_needed
219
+ # call original
220
+ old_method2.bind(self).()
221
+ # ...
222
+ # ...
223
+ # ...
224
+ # after finishing the very complex orginal function
225
+
226
+ # check the pods
227
+ # Although we have did it in prebuild stage, it's not sufficient.
228
+ # Same pod may appear in another target in form of source code.
229
+ # Prebuild.check_one_pod_should_have_only_one_target(self.prebuild_pod_targets)
230
+ self.validate_every_pod_only_have_one_form
231
+
232
+
233
+ # prepare
234
+ cache = []
235
+
236
+ def add_vendered_framework(spec, platform, added_framework_file_path)
237
+ platform_map = spec.attributes_hash[platform]
238
+ if platform_map == nil
239
+ platform_map = {}
240
+ end
241
+ vendored_frameworks = platform_map["vendored_frameworks"] || []
242
+ vendored_frameworks = [vendored_frameworks] if vendored_frameworks.kind_of?(String)
243
+ vf = spec.attributes_hash["vendored_frameworks"] || []
244
+ vf = [vf] if vf.kind_of?(String)
245
+ vendored_frameworks += vf
246
+ vendored_frameworks += [added_framework_file_path]
247
+ spec.attributes_hash["vendored_frameworks"] = vendored_frameworks
248
+ if spec.attributes_hash[platform] != nil
249
+ spec.attributes_hash[platform].delete("vendored_frameworks")
250
+ end
251
+ end
252
+ def empty_source_files(spec)
253
+ spec.attributes_hash["source_files"] = []
254
+ ["ios", "watchos", "tvos", "osx"].each do |plat|
255
+ if spec.attributes_hash[plat] != nil
256
+ spec.attributes_hash[plat]["source_files"] = []
257
+ end
258
+ end
259
+ end
260
+
261
+
262
+ specs = self.analysis_result.specifications
263
+ prebuilt_specs = (specs.select do |spec|
264
+ self.prebuild_pod_names.include? spec.root.name
265
+ end)
266
+
267
+ prebuilt_specs.each do |spec|
268
+
269
+ # Use the prebuild framworks as vendered frameworks
270
+ # get_corresponding_targets
271
+ targets = Pod.fast_get_targets_for_pod_name(spec.root.name, self.pod_targets, cache)
272
+ targets.each do |target|
273
+ # the framework_file_path rule is decided when `install_for_prebuild`,
274
+ # as to compitable with older version and be less wordy.
275
+ framework_file_path = target.framework_name
276
+ framework_file_path = target.name + "/" + framework_file_path if targets.count > 1
277
+ add_vendered_framework(spec, target.platform.name.to_s, framework_file_path)
278
+ end
279
+ # Clean the source files
280
+ # we just add the prebuilt framework to specific platform and set no source files
281
+ # for all platform, so it doesn't support the sence that 'a pod perbuild for one
282
+ # platform and not for another platform.'
283
+ empty_source_files(spec)
284
+
285
+ # to remove the resurce bundle target.
286
+ # When specify the "resource_bundles" in podspec, xcode will generate a bundle
287
+ # target after pod install. But the bundle have already built when the prebuit
288
+ # phase and saved in the framework folder. We will treat it as a normal resource
289
+ # file.
290
+
291
+ if spec.attributes_hash["resource_bundles"]
292
+ bundle_names = spec.attributes_hash["resource_bundles"].keys
293
+ spec.attributes_hash["resource_bundles"] = nil
294
+ spec.attributes_hash["resources"] ||= []
295
+ spec.attributes_hash["resources"] += bundle_names.map{|n| n+".bundle"}
296
+ elsif spec.attributes_hash['ios'] && spec.attributes_hash['ios']["resource_bundles"]
297
+ bundle_names = spec.attributes_hash['ios']["resource_bundles"].keys
298
+ spec.attributes_hash['ios']["resource_bundles"] = nil
299
+ spec.attributes_hash['ios']["resources"] ||= []
300
+ spec.attributes_hash['ios']["resources"] += bundle_names.map{|n| n+".bundle"}
301
+ end
302
+
303
+ # to avoid the warning of missing license
304
+ spec.attributes_hash["license"] = {}
305
+
306
+ end
307
+ end
308
+
309
+ end
310
+
311
+
312
+ # Override the download step to skip download and prepare file in target folder
313
+ old_method = instance_method(:install_source_of_pod)
314
+ define_method(:install_source_of_pod) do |pod_name|
315
+ if Pod::is_prebuild_stage
316
+ tmp = old_method.bind(self).(pod_name)
317
+ else
318
+ # copy from original
319
+ pod_installer = create_pod_installer(pod_name)
320
+ # \copy from original
321
+
322
+ if self.prebuild_pod_names.include? pod_name
323
+ pod_installer.install_for_prebuild!(self.sandbox)
324
+ else
325
+ pod_installer.install!
326
+ end
327
+
328
+ # copy from original
329
+ return @installed_specs.concat(pod_installer.specs_by_platform.values.flatten.uniq)
330
+ # \copy from original
331
+ end
332
+ end
333
+
334
+ end
335
+ end
336
+
337
+ # A fix in embeded frameworks script.
338
+ #
339
+ # The framework file in pod target folder is a symblink. The EmbedFrameworksScript use `readlink`
340
+ # to read the read path. As the symlink is a relative symlink, readlink cannot handle it well. So
341
+ # we override the `readlink` to a fixed version.
342
+ #
343
+ module Pod
344
+ module Generator
345
+ class EmbedFrameworksScript
346
+ old_method = instance_method(:script)
347
+ define_method(:script) do
348
+ script = old_method.bind(self).()
349
+ if not Pod::is_prebuild_stage
350
+ patch = <<-SH.strip_heredoc
351
+ #!/bin/sh
352
+
353
+ # ---- this is added by cocoapods-xlbuild ---
354
+ # Readlink cannot handle relative symlink well, so we override it to a new one
355
+ # If the path isn't an absolute path, we add a realtive prefix.
356
+ old_read_link=`which readlink`
357
+ readlink () {
358
+ path=`$old_read_link "$1"`;
359
+ if [ $(echo "$path" | cut -c 1-1) = '/' ]; then
360
+ echo $path;
361
+ else
362
+ echo "`dirname $1`/$path";
363
+ fi
364
+ }
365
+ # ---
366
+ SH
367
+
368
+ # patch the rsync for copy dSYM symlink
369
+ script = script.gsub "rsync --delete", "rsync --copy-links --delete"
370
+
371
+ script = patch + script
372
+ end
373
+ script
374
+ end
375
+ end
376
+ end
377
+ end
@@ -0,0 +1,193 @@
1
+ # encoding: UTF-8
2
+ require_relative 'helper/podfile_options'
3
+ require_relative 'tool/tool'
4
+
5
+ module Pod
6
+ class Podfile
7
+ module DSL
8
+ # Enable prebuiding for all pods
9
+ # it has a lower priority to other xlbuild settings
10
+ def use_dynamic_binary!
11
+ DSL.prebuild_all = true
12
+ DSL.static_binary = false
13
+ DSL.dont_remove_source_code = true
14
+ end
15
+ # 设置当前swift版本
16
+ def use_swift_version(version)
17
+ DSL.swift_version = version
18
+ end
19
+
20
+ # 设置是否使用静态库
21
+ def use_static_binary!
22
+ DSL.prebuild_all = true
23
+ DSL.static_binary = true
24
+ DSL.dont_remove_source_code = true
25
+ end
26
+
27
+ # 设置是否保存源码,默认 true
28
+ def remove_source_code_for_prebuilt_frameworks!
29
+ DSL.dont_remove_source_code = false
30
+ end
31
+
32
+ # Enable bitcode for prebuilt frameworks
33
+ def enable_bitcode_for_prebuilt_frameworks!
34
+ DSL.bitcode_enabled = true
35
+ end
36
+
37
+ # Add custom xcodebuild option to the prebuilding action
38
+ #
39
+ # You may use this for your special demands. For example: the default archs in dSYMs
40
+ # of prebuilt frameworks is 'arm64 armv7 x86_64', and no 'i386' for 32bit simulator.
41
+ # It may generate a warning when building for a 32bit simulator. You may add following
42
+ # to your podfile
43
+ #
44
+ # ` set_custom_xcodebuild_options_for_prebuilt_frameworks :simulator => "ARCHS=$(ARCHS_STANDARD)" `
45
+ #
46
+ # Another example to disable the generating of dSYM file:
47
+ #
48
+ # ` set_custom_xcodebuild_options_for_prebuilt_frameworks "DEBUG_INFORMATION_FORMAT=dwarf"`
49
+ #
50
+ #
51
+ # @param [String or Hash] options
52
+ #
53
+ # If is a String, it will apply for device and simulator. Use it just like in the commandline.
54
+ # If is a Hash, it should be like this: { :device => "XXXXX", :simulator => "XXXXX" }
55
+ #
56
+ def set_custom_xcodebuild_options_for_prebuilt_frameworks(options)
57
+ if options.kind_of? Hash
58
+ DSL.custom_build_options = [ options[:device] ] unless options[:device].nil?
59
+ DSL.custom_build_options_simulator = [ options[:simulator] ] unless options[:simulator].nil?
60
+ elsif options.kind_of? String
61
+ DSL.custom_build_options = [options]
62
+ DSL.custom_build_options_simulator = [options]
63
+ else
64
+ raise "Wrong type."
65
+ end
66
+ end
67
+
68
+ private
69
+ class_attr_accessor :prebuild_all
70
+ prebuild_all = false
71
+
72
+ class_attr_accessor :swift_version
73
+ swift_version = "5.0" # swift版本默认5.0
74
+
75
+ class_attr_accessor :static_binary
76
+ static_binary = false
77
+
78
+ class_attr_accessor :bitcode_enabled
79
+ bitcode_enabled = false
80
+
81
+ class_attr_accessor :dont_remove_source_code
82
+ dont_remove_source_code = true
83
+
84
+ class_attr_accessor :custom_build_options
85
+ class_attr_accessor :custom_build_options_simulator
86
+ self.custom_build_options = []
87
+ self.custom_build_options_simulator = []
88
+ end
89
+ end
90
+ end
91
+
92
+ Pod::HooksManager.register('cocoapods-xlbuild', :pre_install) do |installer_context|
93
+ require_relative 'helper/feature_switches'
94
+ if Pod.is_prebuild_stage
95
+ next
96
+ end
97
+
98
+ # [Check Environment]
99
+ # check user_framework is on
100
+ podfile = installer_context.podfile
101
+ podfile.target_definition_list.each do |target_definition|
102
+ next if target_definition.prebuild_framework_pod_names.empty?
103
+ if not target_definition.uses_frameworks?
104
+ STDERR.puts "[!] cocoapods-xlbuild requires `use_frameworks!`".red
105
+ exit
106
+ end
107
+ end
108
+
109
+ # -- step 1: prebuild framework ---
110
+ # Execute a sperated pod install, to generate targets for building framework,
111
+ # then compile them to framework files.
112
+ require_relative 'helper/prebuild_sandbox'
113
+
114
+ #Prebuild里面hooke了run_plugins_post_install_hooks方法
115
+ require_relative 'Prebuild'
116
+
117
+ # Pod::UI.puts "火速编译中..."
118
+
119
+ # Fetch original installer (which is running this pre-install hook) options,
120
+ # then pass them to our installer to perform update if needed
121
+ # Looks like this is the most appropriate way to figure out that something should be updated
122
+
123
+ update = nil
124
+ repo_update = nil
125
+
126
+ include ObjectSpace
127
+ ObjectSpace.each_object(Pod::Installer) { |installer|
128
+ update = installer.update
129
+ repo_update = installer.repo_update
130
+ }
131
+
132
+ # control features
133
+ Pod.is_prebuild_stage = true
134
+ Pod::Podfile::DSL.enable_prebuild_patch true # enable sikpping for prebuild targets
135
+ Pod::Installer.force_disable_integration true # don't integrate targets
136
+ Pod::Config.force_disable_write_lockfile true # disbale write lock file for perbuild podfile
137
+ Pod::Installer.disable_install_complete_message true # disable install complete message
138
+
139
+ # make another custom sandbox
140
+ standard_sandbox = installer_context.sandbox
141
+ prebuild_sandbox = Pod::PrebuildSandbox.from_standard_sandbox(standard_sandbox)
142
+
143
+ # get the podfile for prebuild
144
+ prebuild_podfile = Pod::Podfile.from_ruby(podfile.defined_in_file)
145
+
146
+ # install
147
+ lockfile = installer_context.lockfile
148
+ binary_installer = Pod::Installer.new(prebuild_sandbox, prebuild_podfile, lockfile)
149
+
150
+ require_relative 'Integration'
151
+ # Prebuild文件里面也扩展了 Pod::Installer类,同时新增扩展了have_exact_prebuild_cache?方法
152
+ if binary_installer.have_exact_prebuild_cache? && !update
153
+ binary_installer.install_when_cache_hit!
154
+ else
155
+ binary_installer.update = update
156
+ binary_installer.repo_update = repo_update
157
+ binary_installer.install!
158
+ end
159
+
160
+ ##备注上面的install是同步执行的,工程hook了 pod 的方法使得其会先下载源码然后进行xcodebuild编译 编译晚
161
+ #之后才会往下走
162
+
163
+ # reset the environment
164
+ Pod.is_prebuild_stage = false
165
+ Pod::Installer.force_disable_integration false
166
+ Pod::Podfile::DSL.enable_prebuild_patch false
167
+ Pod::Config.force_disable_write_lockfile false
168
+ Pod::Installer.disable_install_complete_message false
169
+ Pod::UserInterface.warnings = [] # clean the warning in the prebuild step, it's duplicated.
170
+
171
+ # -- step 2: pod install ---
172
+ # install
173
+ Pod::UI.puts "🤖 Pod Install " + Time.new.inspect
174
+ # go on the normal install step ...
175
+
176
+ end
177
+
178
+ ## pod 安装依赖的时候会执行install,install的时候会执行run_plugins_post_install_hooks(Prebuildhook了该方法)
179
+ # 只要有触发install方法就会触发如下的
180
+ Pod::HooksManager.register('cocoapods-xlbuild', :post_install) do |installer_context|
181
+ Pod::UI.puts "🤖 Pod Install hook " + Time.new.inspect
182
+ if Pod::Podfile::DSL.static_binary
183
+ Pod::UI.puts "🤖 replace_tagert_copy_source_sh " + Time.new.inspect
184
+ Pod::PrebuildSandbox.replace_tagert_copy_source_sh(installer_context)
185
+ end
186
+
187
+ if !Pod.is_prebuild_stage && Pod::Podfile::DSL.dont_remove_source_code
188
+ Pod::UI.puts "🤖 pod工程关联引用源码 " + Time.new.inspect
189
+ require_relative 'reference/reference_source_code'
190
+ installer_context.refrence_source_code
191
+ end
192
+ end
193
+