cocoapods-binary-gcp 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,199 @@
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
+
9
+ # Enable prebuiding for all pods
10
+ # it has a lower priority to other binary settings
11
+ def all_binary!
12
+ DSL.prebuild_all = true
13
+ end
14
+
15
+ # - excepts: an array of name
16
+ def all_binary_except(excepts)
17
+ DSL.prebuild_all = true
18
+ DSL.except_binary_list = excepts
19
+ end
20
+
21
+ # Enable bitcode for prebuilt frameworks
22
+ def enable_bitcode_for_prebuilt_frameworks!
23
+ DSL.bitcode_enabled = true
24
+ end
25
+
26
+ # Don't remove source code of prebuilt pods
27
+ # It may speed up the pod install if git didn't
28
+ # include the `Pods` folder
29
+ def keep_source_code_for_prebuilt_frameworks!
30
+ DSL.dont_remove_source_code = true
31
+ end
32
+
33
+ # Enable shared cache of prebuild frameworks
34
+ # Frameworks are stored inside cocoapods cache folder
35
+ #
36
+ # Location: ~/Library/Caches/CocoaPods/Prebuilt/
37
+ # Structure: <xcode-version>/<framework-name>/<framework-version>/<options hash>/
38
+ # Options hash depends on:
39
+ # - bitcode(enable_bitcode_for_prebuilt_frameworks!);
40
+ # - custom options(set_custom_xcodebuild_options_for_prebuilt_frameworks);
41
+ # - platform name(ios, osx);
42
+ # def use_shared_cache!
43
+ # DSL.shared_cache_enabled = true
44
+ # end
45
+
46
+
47
+ # Options hash depends on:
48
+ # - bucket: bucketName
49
+ def use_gcp_cache(options)
50
+ DSL.shared_cache_enabled = true
51
+ DSL.shared_gcp_cache_enabled = true
52
+ DSL.gcp_options = options
53
+ end
54
+
55
+ # Add custom xcodebuild option to the prebuilding action
56
+ #
57
+ # You may use this for your special demands. For example: the default archs in dSYMs
58
+ # of prebuilt frameworks is 'arm64 armv7 x86_64', and no 'i386' for 32bit simulator.
59
+ # It may generate a warning when building for a 32bit simulator. You may add following
60
+ # to your podfile
61
+ #
62
+ # ` set_custom_xcodebuild_options_for_prebuilt_frameworks :simulator => "ARCHS=$(ARCHS_STANDARD)" `
63
+ #
64
+ # Another example to disable the generating of dSYM file:
65
+ #
66
+ # ` set_custom_xcodebuild_options_for_prebuilt_frameworks "DEBUG_INFORMATION_FORMAT=dwarf"`
67
+ #
68
+ #
69
+ # @param [String or Hash] options
70
+ #
71
+ # If is a String, it will apply for device and simulator. Use it just like in the commandline.
72
+ # If is a Hash, it should be like this: { :device => "XXXXX", :simulator => "XXXXX" }
73
+ #
74
+ def set_custom_xcodebuild_options_for_prebuilt_frameworks(options)
75
+ if options.kind_of? Hash
76
+ DSL.custom_build_options = [ options[:device] ] unless options[:device].nil?
77
+ DSL.custom_build_options_simulator = [ options[:simulator] ] unless options[:simulator].nil?
78
+ elsif options.kind_of? String
79
+ DSL.custom_build_options = [options]
80
+ DSL.custom_build_options_simulator = [options]
81
+ else
82
+ raise "Wrong type."
83
+ end
84
+ end
85
+
86
+ private
87
+ class_attr_accessor :prebuild_all
88
+ prebuild_all = false
89
+
90
+ class_attr_accessor :bitcode_enabled
91
+ bitcode_enabled = false
92
+
93
+ class_attr_accessor :dont_remove_source_code
94
+ dont_remove_source_code = false
95
+
96
+ class_attr_accessor :shared_cache_enabled
97
+ shared_cache_enabled = false
98
+
99
+ class_attr_accessor :shared_gcp_cache_enabled
100
+ shared_gcp_cache_enabled = false
101
+
102
+ class_attr_accessor :gcp_options
103
+ gcp_options = {}
104
+
105
+ class_attr_accessor :custom_build_options
106
+ class_attr_accessor :custom_build_options_simulator
107
+ self.custom_build_options = []
108
+ self.custom_build_options_simulator = []
109
+
110
+ class_attr_accessor :except_binary_list
111
+ self.except_binary_list = []
112
+ end
113
+ end
114
+ end
115
+
116
+ Pod::HooksManager.register('cocoapods-binary', :pre_install) do |installer_context|
117
+
118
+ require_relative 'helper/feature_switches'
119
+ if Pod.is_prebuild_stage
120
+ next
121
+ end
122
+
123
+ # [Check Environment]
124
+ # check user_framework is on
125
+ podfile = installer_context.podfile
126
+ podfile.target_definition_list.each do |target_definition|
127
+ next if target_definition.prebuild_framework_pod_names.empty?
128
+ if not target_definition.uses_frameworks?
129
+ STDERR.puts "[!] Cocoapods-binary requires `use_frameworks!`".red
130
+ exit
131
+ end
132
+ end
133
+
134
+
135
+ # -- step 1: prebuild framework ---
136
+ # Execute a sperated pod install, to generate targets for building framework,
137
+ # then compile them to framework files.
138
+ require_relative 'helper/prebuild_sandbox'
139
+ require_relative 'Prebuild'
140
+
141
+ Pod::UI.puts "🚀 Prebuild frameworks"
142
+
143
+ # Fetch original installer (which is running this pre-install hook) options,
144
+ # then pass them to our installer to perform update if needed
145
+ # Looks like this is the most appropriate way to figure out that something should be updated
146
+
147
+ update = nil
148
+ repo_update = nil
149
+
150
+ include ObjectSpace
151
+ ObjectSpace.each_object(Pod::Installer) { |installer|
152
+ update = installer.update
153
+ repo_update = installer.repo_update
154
+ }
155
+
156
+ # control features
157
+ Pod.is_prebuild_stage = true
158
+ Pod::Podfile::DSL.enable_prebuild_patch true # enable sikpping for prebuild targets
159
+ Pod::Installer.force_disable_integration true # don't integrate targets
160
+ Pod::Config.force_disable_write_lockfile true # disbale write lock file for perbuild podfile
161
+ Pod::Installer.disable_install_complete_message true # disable install complete message
162
+
163
+ # make another custom sandbox
164
+ standard_sandbox = installer_context.sandbox
165
+ prebuild_sandbox = Pod::PrebuildSandbox.from_standard_sandbox(standard_sandbox)
166
+
167
+ # get the podfile for prebuild
168
+ prebuild_podfile = Pod::Podfile.from_ruby(podfile.defined_in_file)
169
+
170
+ # install
171
+ lockfile = installer_context.lockfile
172
+ binary_installer = Pod::Installer.new(prebuild_sandbox, prebuild_podfile, lockfile)
173
+
174
+ if binary_installer.have_exact_prebuild_cache? && !update
175
+ binary_installer.install_when_cache_hit!
176
+ else
177
+ binary_installer.update = update
178
+ binary_installer.repo_update = repo_update
179
+ binary_installer.install!
180
+ end
181
+
182
+
183
+ # reset the environment
184
+ Pod.is_prebuild_stage = false
185
+ Pod::Installer.force_disable_integration false
186
+ Pod::Podfile::DSL.enable_prebuild_patch false
187
+ Pod::Config.force_disable_write_lockfile false
188
+ Pod::Installer.disable_install_complete_message false
189
+ Pod::UserInterface.warnings = [] # clean the warning in the prebuild step, it's duplicated.
190
+
191
+
192
+ # -- step 2: pod install ---
193
+ # install
194
+ Pod::UI.puts "\n"
195
+ Pod::UI.puts "🤖 Pod Install"
196
+ require_relative 'Integration'
197
+ # go on the normal install step ...
198
+ end
199
+
@@ -0,0 +1,273 @@
1
+ require_relative 'rome/build_framework'
2
+ require_relative 'helper/passer'
3
+ require_relative 'helper/target_checker'
4
+ require_relative 'helper/shared_cache'
5
+
6
+
7
+ # patch prebuild ability
8
+ module Pod
9
+ class Installer
10
+
11
+
12
+ private
13
+
14
+ def local_manifest
15
+ if not @local_manifest_inited
16
+ @local_manifest_inited = true
17
+ raise "This method should be call before generate project" unless self.analysis_result == nil
18
+ @local_manifest = self.sandbox.manifest
19
+ end
20
+ @local_manifest
21
+ end
22
+
23
+ # @return [Analyzer::SpecsState]
24
+ def prebuild_pods_changes
25
+ return nil if local_manifest.nil?
26
+ if @prebuild_pods_changes.nil?
27
+ changes = local_manifest.detect_changes_with_podfile(podfile)
28
+ @prebuild_pods_changes = Analyzer::SpecsState.new(changes)
29
+ # save the chagnes info for later stage
30
+ Pod::Prebuild::Passer.prebuild_pods_changes = @prebuild_pods_changes
31
+ end
32
+ @prebuild_pods_changes
33
+ end
34
+
35
+
36
+ public
37
+
38
+ # check if need to prebuild
39
+ def have_exact_prebuild_cache?
40
+ # check if need build frameworks
41
+ return false if local_manifest == nil
42
+
43
+ changes = prebuild_pods_changes
44
+ added = changes.added
45
+ changed = changes.changed
46
+ unchanged = changes.unchanged
47
+ deleted = changes.deleted
48
+
49
+ exsited_framework_pod_names = sandbox.exsited_framework_pod_names
50
+ missing = unchanged.select do |pod_name|
51
+ not exsited_framework_pod_names.include?(pod_name)
52
+ end
53
+
54
+ needed = (added + changed + deleted + missing)
55
+ return needed.empty?
56
+ end
57
+
58
+
59
+ # The install method when have completed cache
60
+ def install_when_cache_hit!
61
+ # just print log
62
+ self.sandbox.exsited_framework_target_names.each do |name|
63
+ UI.puts "Using #{name}"
64
+ end
65
+ end
66
+
67
+
68
+ # Build the needed framework files
69
+ def prebuild_frameworks!
70
+
71
+ # build options
72
+ sandbox_path = sandbox.root
73
+ existed_framework_folder = sandbox.generate_framework_path
74
+
75
+ options = [
76
+ Podfile::DSL.bitcode_enabled,
77
+ Podfile::DSL.custom_build_options,
78
+ Podfile::DSL.custom_build_options_simulator
79
+ ]
80
+ targets = []
81
+
82
+ if local_manifest != nil
83
+
84
+ changes = prebuild_pods_changes
85
+ added = changes.added
86
+ changed = changes.changed
87
+ unchanged = changes.unchanged
88
+ deleted = changes.deleted
89
+
90
+ existed_framework_folder.mkdir unless existed_framework_folder.exist?
91
+ exsited_framework_pod_names = sandbox.exsited_framework_pod_names
92
+
93
+ # additions
94
+ missing = unchanged.select do |pod_name|
95
+ not exsited_framework_pod_names.include?(pod_name)
96
+ end
97
+
98
+
99
+ root_names_to_update = (added + changed + missing)
100
+
101
+ # transform names to targets
102
+ cache = []
103
+ targets = root_names_to_update.map do |pod_name|
104
+ tars = Pod.fast_get_targets_for_pod_name(pod_name, self.pod_targets, cache)
105
+ if tars.nil? || tars.empty?
106
+ raise "There's no target named (#{pod_name}) in Pod.xcodeproj.\n #{self.pod_targets.map(&:name)}" if t.nil?
107
+ end
108
+ tars
109
+ end.flatten
110
+
111
+ # add the dependencies
112
+ dependency_targets = targets.map {|t| t.recursive_dependent_targets }.flatten.uniq || []
113
+ # filter already built dependencies
114
+ dependency_targets = dependency_targets.reject { |t|
115
+ local_manifest.version(t.name).to_s.eql? t.version.to_s
116
+ }
117
+
118
+ targets = (targets + dependency_targets).uniq
119
+ else
120
+ targets = self.pod_targets
121
+ end
122
+
123
+ # frameworks which mark binary true, should be filtered before prebuild
124
+
125
+ prebuild_framework_pod_names = []
126
+ podfile.target_definition_list.each do |target_definition|
127
+ next if target_definition.prebuild_framework_pod_names.empty?
128
+ prebuild_framework_pod_names += target_definition.prebuild_framework_pod_names
129
+ end
130
+
131
+
132
+ targets = targets
133
+ .reject {|pod_target| sandbox.local?(pod_target.pod_name) }
134
+ .select {|pod_target| prebuild_framework_pod_names.include?(pod_target.pod_name) }
135
+
136
+ # if not Pod::Podfile::DSL.except_binary_list.nil?
137
+ # targets = targets.reject { |pod_target| Pod::Podfile::DSL.except_binary_list.include?(pod_target.pod_name) }
138
+ # end
139
+
140
+ # build!
141
+ Pod::UI.puts "Prebuild frameworks (total #{targets.count})"
142
+ Pod::Prebuild.remove_build_dir(sandbox_path)
143
+ targets.each do |target|
144
+ if !target.should_build?
145
+ UI.puts "Prebuilding #{target.label}"
146
+ next
147
+ end
148
+
149
+ output_path = sandbox.framework_folder_path_for_target_name(target.name)
150
+ output_path.mkpath unless output_path.exist?
151
+
152
+ if Prebuild::SharedCache.has?(target, options)
153
+ framework_cache_path = Prebuild::SharedCache.framework_cache_path_for(target, options)
154
+ UI.puts "Using #{target.label} from cache"
155
+ FileUtils.cp_r "#{framework_cache_path}/.", output_path
156
+ else
157
+ min_deployment_target = aggregate_targets
158
+ .select { |t| t.pod_targets.include?(target) }
159
+ .map(&:platform)
160
+ .map(&:deployment_target)
161
+ .max
162
+
163
+ Pod::Prebuild.build(sandbox_path, target, output_path, min_deployment_target, *options)
164
+ Prebuild::SharedCache.cache(target, output_path, options)
165
+ end
166
+
167
+ # save the resource paths for later installing
168
+ if target.static_framework? and !target.resource_paths.empty?
169
+ framework_path = output_path + target.framework_name
170
+ standard_sandbox_path = sandbox.standard_sanbox_path
171
+
172
+ resources = begin
173
+ if Pod::VERSION.start_with? "1.5"
174
+ target.resource_paths
175
+ else
176
+ # resource_paths is Hash{String=>Array<String>} on 1.6 and above
177
+ # (use AFNetworking to generate a demo data)
178
+ # https://github.com/leavez/cocoapods-binary/issues/50
179
+ target.resource_paths.values.flatten
180
+ end
181
+ end
182
+ raise "Wrong type: #{resources}" unless resources.kind_of? Array
183
+
184
+ path_objects = resources.map do |path|
185
+ object = Prebuild::Passer::ResourcePath.new
186
+ object.real_file_path = framework_path + File.basename(path)
187
+ object.target_file_path = path.gsub('${PODS_ROOT}', standard_sandbox_path.to_s) if path.start_with? '${PODS_ROOT}'
188
+ object.target_file_path = path.gsub("${PODS_CONFIGURATION_BUILD_DIR}", standard_sandbox_path.to_s) if path.start_with? "${PODS_CONFIGURATION_BUILD_DIR}"
189
+ object
190
+ end
191
+ Prebuild::Passer.resources_to_copy_for_static_framework[target.name] = path_objects
192
+ end
193
+
194
+ end
195
+ Pod::Prebuild.remove_build_dir(sandbox_path)
196
+
197
+
198
+ # copy vendored libraries and frameworks
199
+ targets.each do |target|
200
+ root_path = self.sandbox.pod_dir(target.name)
201
+ target_folder = sandbox.framework_folder_path_for_target_name(target.name)
202
+
203
+ # If target shouldn't build, we copy all the original files
204
+ # This is for target with only .a and .h files
205
+ if not target.should_build?
206
+ Prebuild::Passer.target_names_to_skip_integration_framework << target.name
207
+ FileUtils.cp_r(root_path, target_folder, :remove_destination => true)
208
+ next
209
+ end
210
+
211
+ target.spec_consumers.each do |consumer|
212
+ file_accessor = Sandbox::FileAccessor.new(root_path, consumer)
213
+ lib_paths = file_accessor.vendored_frameworks || []
214
+ lib_paths += file_accessor.vendored_libraries
215
+ # @TODO dSYM files
216
+ lib_paths.each do |lib_path|
217
+ relative = lib_path.relative_path_from(root_path)
218
+ destination = target_folder + relative
219
+ destination.dirname.mkpath unless destination.dirname.exist?
220
+ FileUtils.cp_r(lib_path, destination, :remove_destination => true)
221
+ end
222
+ end
223
+ end
224
+
225
+ # save the pod_name for prebuild framwork in sandbox
226
+ targets.each do |target|
227
+ sandbox.save_pod_name_for_target target
228
+ end
229
+
230
+ # Remove useless files
231
+ # remove useless pods
232
+ all_needed_names = self.pod_targets.map(&:name).uniq
233
+ useless_target_names = sandbox.exsited_framework_target_names.reject do |name|
234
+ all_needed_names.include? name
235
+ end
236
+ useless_target_names.each do |name|
237
+ path = sandbox.framework_folder_path_for_target_name(name)
238
+ path.rmtree if path.exist?
239
+ end
240
+
241
+ if not Podfile::DSL.dont_remove_source_code
242
+ # only keep manifest.lock and framework folder in _Prebuild
243
+ to_remain_files = ["Manifest.lock", File.basename(existed_framework_folder)]
244
+ to_delete_files = sandbox_path.children.select do |file|
245
+ filename = File.basename(file)
246
+ not to_remain_files.include?(filename)
247
+ end
248
+ to_delete_files.each do |path|
249
+ path.rmtree if path.exist?
250
+ end
251
+ else
252
+ # just remove the tmp files
253
+ path = sandbox.root + 'Manifest.lock.tmp'
254
+ path.rmtree if path.exist?
255
+ end
256
+
257
+
258
+
259
+ end
260
+
261
+
262
+ # patch the post install hook
263
+ old_method2 = instance_method(:run_plugins_post_install_hooks)
264
+ define_method(:run_plugins_post_install_hooks) do
265
+ old_method2.bind(self).()
266
+ if Pod::is_prebuild_stage
267
+ self.prebuild_frameworks!
268
+ end
269
+ end
270
+
271
+
272
+ end
273
+ end