cocoapods-binary-cache 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +7 -0
  2. data/lib/cocoapods-binary-cache.rb +4 -0
  3. data/lib/cocoapods-binary-cache/cache/all.rb +9 -0
  4. data/lib/cocoapods-binary-cache/cache/validation_result.rb +69 -0
  5. data/lib/cocoapods-binary-cache/cache/validator.rb +21 -0
  6. data/lib/cocoapods-binary-cache/cache/validator_accumulated.rb +4 -0
  7. data/lib/cocoapods-binary-cache/cache/validator_base.rb +92 -0
  8. data/lib/cocoapods-binary-cache/cache/validator_dependencies_graph.rb +20 -0
  9. data/lib/cocoapods-binary-cache/cache/validator_dev_pods.rb +22 -0
  10. data/lib/cocoapods-binary-cache/cache/validator_exclusion.rb +14 -0
  11. data/lib/cocoapods-binary-cache/cache/validator_non_dev_pods.rb +13 -0
  12. data/lib/cocoapods-binary-cache/cache/validator_with_podfile.rb +9 -0
  13. data/lib/cocoapods-binary-cache/dependencies_graph/dependencies_graph.rb +95 -0
  14. data/lib/cocoapods-binary-cache/dependencies_graph/graph_visualizer.rb +74 -0
  15. data/lib/cocoapods-binary-cache/gem_version.rb +6 -0
  16. data/lib/cocoapods-binary-cache/helper/benchmark_show.rb +11 -0
  17. data/lib/cocoapods-binary-cache/helper/checksum.rb +12 -0
  18. data/lib/cocoapods-binary-cache/helper/json.rb +37 -0
  19. data/lib/cocoapods-binary-cache/helper/lockfile.rb +67 -0
  20. data/lib/cocoapods-binary-cache/helper/path_utils.rb +8 -0
  21. data/lib/cocoapods-binary-cache/helper/podspec.rb +17 -0
  22. data/lib/cocoapods-binary-cache/hooks/post_install.rb +16 -0
  23. data/lib/cocoapods-binary-cache/hooks/pre_install.rb +141 -0
  24. data/lib/cocoapods-binary-cache/main.rb +21 -0
  25. data/lib/cocoapods-binary-cache/pod-binary/LICENSE.txt +22 -0
  26. data/lib/cocoapods-binary-cache/pod-binary/helper/detected_prebuilt_pods/installer.rb +25 -0
  27. data/lib/cocoapods-binary-cache/pod-binary/helper/detected_prebuilt_pods/target_definition.rb +36 -0
  28. data/lib/cocoapods-binary-cache/pod-binary/helper/feature_switches.rb +90 -0
  29. data/lib/cocoapods-binary-cache/pod-binary/helper/names.rb +36 -0
  30. data/lib/cocoapods-binary-cache/pod-binary/helper/passer.rb +25 -0
  31. data/lib/cocoapods-binary-cache/pod-binary/helper/podfile_options.rb +2 -0
  32. data/lib/cocoapods-binary-cache/pod-binary/helper/prebuild_sandbox.rb +71 -0
  33. data/lib/cocoapods-binary-cache/pod-binary/helper/target_checker.rb +45 -0
  34. data/lib/cocoapods-binary-cache/pod-binary/integration.rb +12 -0
  35. data/lib/cocoapods-binary-cache/pod-binary/integration/alter_specs.rb +93 -0
  36. data/lib/cocoapods-binary-cache/pod-binary/integration/patch/embed_framework_script.rb +36 -0
  37. data/lib/cocoapods-binary-cache/pod-binary/integration/patch/resolve_dependencies.rb +23 -0
  38. data/lib/cocoapods-binary-cache/pod-binary/integration/patch/source_installation.rb +28 -0
  39. data/lib/cocoapods-binary-cache/pod-binary/integration/remove_target_files.rb +29 -0
  40. data/lib/cocoapods-binary-cache/pod-binary/integration/source_installer.rb +111 -0
  41. data/lib/cocoapods-binary-cache/pod-binary/integration/validation.rb +20 -0
  42. data/lib/cocoapods-binary-cache/pod-binary/prebuild.rb +224 -0
  43. data/lib/cocoapods-binary-cache/pod-binary/prebuild_dsl.rb +69 -0
  44. data/lib/cocoapods-binary-cache/pod-binary/prebuild_hook.rb +11 -0
  45. data/lib/cocoapods-binary-cache/pod-binary/tool/tool.rb +12 -0
  46. data/lib/cocoapods-binary-cache/pod-rome/LICENSE.txt +22 -0
  47. data/lib/cocoapods-binary-cache/pod-rome/build_framework.rb +247 -0
  48. data/lib/cocoapods-binary-cache/prebuild_cache.rb +49 -0
  49. data/lib/cocoapods-binary-cache/prebuild_output/metadata.rb +47 -0
  50. data/lib/cocoapods-binary-cache/prebuild_output/output.rb +71 -0
  51. data/lib/cocoapods-binary-cache/scheme_editor.rb +35 -0
  52. data/lib/cocoapods-binary-cache/state_store.rb +11 -0
  53. data/lib/cocoapods-binary-cache/ui.rb +9 -0
  54. data/lib/cocoapods_plugin.rb +5 -0
  55. data/lib/command/binary.rb +18 -0
  56. data/lib/command/config.rb +31 -0
  57. data/lib/command/executor/base.rb +20 -0
  58. data/lib/command/executor/fetcher.rb +44 -0
  59. data/lib/command/executor/prebuilder.rb +58 -0
  60. data/lib/command/executor/pusher.rb +19 -0
  61. data/lib/command/executor/visualizer.rb +20 -0
  62. data/lib/command/fetch.rb +23 -0
  63. data/lib/command/helper/zip.rb +20 -0
  64. data/lib/command/prebuild.rb +29 -0
  65. data/lib/command/visualize.rb +30 -0
  66. metadata +193 -0
@@ -0,0 +1,20 @@
1
+ module Pod
2
+ class Installer
3
+ def validate_every_pod_only_have_one_form
4
+ multi_targets_pods = pod_targets
5
+ .group_by(&:pod_name)
6
+ .select do |_, targets|
7
+ is_multi_targets = targets.map { |t| t.platform.name }.uniq.count > 1
8
+ is_multi_forms = targets.map { |t| prebuilt_pod_targets.include?(t) }.uniq.count > 1
9
+ is_multi_targets && is_multi_forms
10
+ end
11
+ return if multi_targets_pods.empty?
12
+
13
+ warnings = "One pod can only be prebuilt or not prebuilt. These pod have different forms in multiple targets:\n"
14
+ warnings += multi_targets_pods
15
+ .map { |name, targets| " #{name}: #{targets.map { |t| t.platform.name }}" }
16
+ .join("\n")
17
+ raise Informative, warnings
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,224 @@
1
+ require "fileutils"
2
+ require_relative "../pod-rome/build_framework"
3
+ require_relative "../prebuild_output/output"
4
+ require_relative "helper/passer"
5
+ require_relative "helper/target_checker"
6
+
7
+ # patch prebuild ability
8
+ module Pod
9
+ class PrebuildInstaller < Installer
10
+ def initialize(options)
11
+ super(options[:sandbox], options[:podfile], options[:lockfile])
12
+ @cache_validation = options[:cache_validation]
13
+ end
14
+
15
+ private
16
+
17
+ def local_manifest
18
+ @local_manifest ||= sandbox.manifest
19
+ end
20
+
21
+ # @return [Analyzer::SpecsState]
22
+ def prebuild_pods_changes
23
+ return nil if local_manifest.nil?
24
+
25
+ if @prebuild_pods_changes.nil?
26
+ changes = local_manifest.detect_changes_with_podfile(podfile)
27
+ @prebuild_pods_changes = Analyzer::SpecsState.new(changes)
28
+ # save the chagnes info for later stage
29
+ Pod::Prebuild::Passer.prebuild_pods_changes = @prebuild_pods_changes
30
+ end
31
+ @prebuild_pods_changes
32
+ end
33
+
34
+ def blacklisted?(name)
35
+ PodPrebuild::StateStore.excluded_pods.include?(name)
36
+ end
37
+
38
+ def cache_hit?(name)
39
+ @cache_validation.hit?(name)
40
+ end
41
+
42
+ def should_not_prebuild_vendor_pod(name)
43
+ return true if blacklisted?(name)
44
+ return false if Pod::Podfile::DSL.prebuild_all_vendor_pods
45
+
46
+ cache_hit?(name)
47
+ end
48
+
49
+ public
50
+
51
+ def prebuild_output
52
+ @prebuild_output ||= PodPrebuild::Output.new(sandbox)
53
+ end
54
+
55
+ # Build the needed framework files
56
+ def prebuild_frameworks!
57
+ UI.puts "Start prebuild_frameworks"
58
+
59
+ # build options
60
+ sandbox_path = sandbox.root
61
+ existed_framework_folder = sandbox.generate_framework_path
62
+ bitcode_enabled = Pod::Podfile::DSL.bitcode_enabled
63
+ targets = []
64
+
65
+ if Pod::Podfile::DSL.prebuild_all_vendor_pods
66
+ UI.puts "Rebuild all vendor frameworks"
67
+ targets = pod_targets
68
+ elsif !local_manifest.nil?
69
+ UI.puts "Update some frameworks"
70
+ changes = prebuild_pods_changes
71
+ added = changes.added
72
+ changed = changes.changed
73
+ unchanged = changes.unchanged
74
+
75
+ existed_framework_folder.mkdir unless existed_framework_folder.exist?
76
+ exsited_framework_pod_names = sandbox.exsited_framework_pod_names
77
+
78
+ # additions
79
+ missing = unchanged.reject { |pod_name| exsited_framework_pod_names.include?(pod_name) }
80
+
81
+ root_names_to_update = (added + changed + missing)
82
+ root_names_to_update += PodPrebuild::StateStore.cache_validation.missed
83
+
84
+ # transform names to targets
85
+ cache = []
86
+ targets = root_names_to_update.map do |pod_name|
87
+ tars = Pod.fast_get_targets_for_pod_name(pod_name, pod_targets, cache) || []
88
+ raise "There's no target named (#{pod_name}) in Pod.xcodeproj" if tars.empty?
89
+
90
+ tars
91
+ end.flatten
92
+
93
+ # add the dendencies
94
+ dependency_targets = targets.map(&:recursive_dependent_targets).flatten.uniq || []
95
+ targets = (targets + dependency_targets).uniq
96
+ else
97
+ UI.puts "Rebuild all frameworks"
98
+ targets = pod_targets
99
+ end
100
+
101
+ targets = targets.reject { |pod_target| should_not_prebuild_vendor_pod(pod_target.name) }
102
+ targets = targets.reject { |pod_target| sandbox.local?(pod_target.pod_name) } unless Podfile::DSL.dev_pods_enabled
103
+
104
+ # build!
105
+ Pod::UI.puts "Prebuild frameworks (total #{targets.count})"
106
+ Pod::UI.puts targets.map(&:name)
107
+
108
+ Pod::Prebuild.remove_build_dir(sandbox_path)
109
+ targets.each do |target|
110
+ unless target.should_build?
111
+ Pod::UI.puts "Skip prebuilding #{target.label} because of no source files".yellow
112
+ next
113
+ end
114
+
115
+ output_path = sandbox.framework_folder_path_for_target_name(target.name)
116
+ output_path.mkpath unless output_path.exist?
117
+ Pod::Prebuild.build(
118
+ sandbox_path,
119
+ target,
120
+ Pod::Podfile::DSL.prebuild_config,
121
+ output_path,
122
+ bitcode_enabled,
123
+ Pod::Podfile::DSL.custom_device_build_options,
124
+ Pod::Podfile::DSL.custom_simulator_build_options
125
+ )
126
+ collect_metadata(target, output_path)
127
+ end
128
+ Pod::Prebuild.remove_build_dir(sandbox_path)
129
+
130
+ # copy vendored libraries and frameworks
131
+ targets.each do |target|
132
+ root_path = sandbox.pod_dir(target.name)
133
+ target_folder = sandbox.framework_folder_path_for_target_name(target.name)
134
+
135
+ # If target shouldn't build, we copy all the original files
136
+ # This is for target with only .a and .h files
137
+ unless target.should_build?
138
+ Prebuild::Passer.target_names_to_skip_integration_framework << target.name
139
+ FileUtils.cp_r(root_path, target_folder, :remove_destination => true)
140
+ next
141
+ end
142
+
143
+ target.spec_consumers.each do |consumer|
144
+ file_accessor = Sandbox::FileAccessor.new(root_path, consumer)
145
+ lib_paths = file_accessor.vendored_frameworks || []
146
+ lib_paths += file_accessor.vendored_libraries
147
+ # @TODO dSYM files
148
+ lib_paths.each do |lib_path|
149
+ relative = lib_path.relative_path_from(root_path)
150
+ destination = target_folder + relative
151
+ destination.dirname.mkpath unless destination.dirname.exist?
152
+ FileUtils.cp_r(lib_path, destination, :remove_destination => true)
153
+ end
154
+ end
155
+ end
156
+
157
+ # save the pod_name for prebuild framwork in sandbox
158
+ targets.each do |target|
159
+ sandbox.save_pod_name_for_target target
160
+ end
161
+
162
+ # Remove useless files
163
+ # remove useless pods
164
+ all_needed_names = pod_targets.map(&:name).uniq
165
+ useless_target_names = sandbox.exsited_framework_target_names.reject do |name|
166
+ all_needed_names.include? name
167
+ end
168
+ useless_target_names.each do |name|
169
+ UI.puts "Remove: #{name}"
170
+ path = sandbox.framework_folder_path_for_target_name(name)
171
+ path.rmtree if path.exist?
172
+ end
173
+
174
+ if Podfile::DSL.dont_remove_source_code
175
+ # just remove the tmp files
176
+ path = sandbox.root + "Manifest.lock.tmp"
177
+ path.rmtree if path.exist?
178
+ else
179
+ # only keep manifest.lock and framework folder in _Prebuild
180
+ to_remain_files = ["Manifest.lock", File.basename(existed_framework_folder)]
181
+ to_delete_files = sandbox_path.children.reject { |file| to_remain_files.include?(File.basename(file)) }
182
+ to_delete_files.each { |file| file.rmtree if file.exist? }
183
+ end
184
+
185
+ updated_target_names = targets.map { |target| target.label.to_s }
186
+ deleted_target_names = useless_target_names
187
+ Pod::UI.puts "Targets to prebuild: #{updated_target_names}"
188
+ Pod::UI.puts "Targets to cleanup: #{deleted_target_names}"
189
+
190
+ prebuild_output.write_delta_file(updated_target_names, deleted_target_names)
191
+ prebuild_output.process_prebuilt_dev_pods
192
+ end
193
+
194
+ def clean_delta_file
195
+ prebuild_output.clean_delta_file
196
+ end
197
+
198
+ def collect_metadata(target, output_path)
199
+ metadata = PodPrebuild::Metadata.in_dir(output_path)
200
+ metadata.framework_name = target.framework_name
201
+ metadata.static_framework = target.static_framework?
202
+ resource_paths = target.resource_paths
203
+ metadata.resources = resource_paths.is_a?(Hash) ? resource_paths.values.flatten : resource_paths
204
+ metadata.resource_bundles = target
205
+ .file_accessors
206
+ .map { |f| f.resource_bundles.keys }
207
+ .flatten
208
+ .map { |name| "#{name}.bundle" }
209
+ metadata.build_settings = pods_project.targets
210
+ .detect { |native_target| native_target.name == target.name }
211
+ .build_configurations
212
+ .detect { |config| config.name == Pod::Podfile::DSL.prebuild_config }
213
+ .build_settings
214
+ metadata.save!
215
+ end
216
+
217
+ # patch the post install hook
218
+ old_method2 = instance_method(:run_plugins_post_install_hooks)
219
+ define_method(:run_plugins_post_install_hooks) do
220
+ old_method2.bind(self).call
221
+ prebuild_frameworks! if Pod.is_prebuild_stage && Pod::Podfile::DSL.prebuild_job?
222
+ end
223
+ end
224
+ end
@@ -0,0 +1,69 @@
1
+ require_relative "tool/tool"
2
+
3
+ module Pod
4
+ class Podfile
5
+ module DSL
6
+ def config_cocoapods_binary_cache(options)
7
+ apply_config = lambda do |config|
8
+ DSL.send("#{config}=", options[config]) unless options[config].nil?
9
+ end
10
+
11
+ apply_config.call(:prebuild_config)
12
+ apply_config.call(:prebuild_job)
13
+ apply_config.call(:prebuild_all) # TODO (thuyen): Revise this option
14
+ apply_config.call(:prebuild_all_vendor_pods)
15
+ apply_config.call(:excluded_pods)
16
+ apply_config.call(:dev_pods_enabled)
17
+ apply_config.call(:bitcode_enabled)
18
+ apply_config.call(:dont_remove_source_code)
19
+ apply_config.call(:custom_device_build_options)
20
+ apply_config.call(:custom_simulator_build_options)
21
+ apply_config.call(:save_cache_validation_to)
22
+ apply_config.call(:validate_prebuilt_settings)
23
+ end
24
+
25
+ @prebuild_config = "Debug"
26
+ @prebuild_job = false
27
+ @prebuild_all = false
28
+ @prebuild_all_vendor_pods = false
29
+ @excluded_pods = Set.new
30
+ @dev_pods_enabled = false
31
+ @bitcode_enabled = false
32
+ @dont_remove_source_code = false
33
+ @custom_device_build_options = []
34
+ @custom_simulator_build_options = []
35
+ @save_cache_validation_to = nil
36
+ # A proc to validate the provided build settings (per target) with the build settings of the prebuilt frameworks
37
+ # For example, in Podfile:
38
+ # -----------------------------------------------
39
+ # validate_prebuilt_settings do |target|
40
+ # settings = {}
41
+ # settings["MACH_O_TYPE"] == "staticlib"
42
+ # settings["SWIFT_VERSION"] == swift_version_of(target)
43
+ # settings
44
+ # end
45
+ # -----------------------------------------------
46
+ @validate_prebuilt_settings = nil
47
+
48
+ class << self
49
+ attr_accessor :prebuild_config
50
+ attr_accessor :prebuild_job
51
+ attr_accessor :prebuild_all
52
+ attr_accessor :prebuild_all_vendor_pods
53
+ attr_accessor :excluded_pods
54
+ attr_accessor :dev_pods_enabled
55
+ attr_accessor :bitcode_enabled
56
+ attr_accessor :dont_remove_source_code
57
+ attr_accessor :custom_device_build_options
58
+ attr_accessor :custom_simulator_build_options
59
+ attr_accessor :save_cache_validation_to
60
+ attr_accessor :validate_prebuilt_settings
61
+
62
+ alias prebuild_job? prebuild_job
63
+ alias prebuild_all? prebuild_all
64
+ alias prebuild_all_vendor_pods? prebuild_all_vendor_pods
65
+ alias dev_pods_enabled? dev_pods_enabled
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,11 @@
1
+ require_relative "helper/passer"
2
+ require_relative "helper/podfile_options"
3
+ require_relative "helper/prebuild_sandbox"
4
+
5
+ Pod::HooksManager.register("cocoapods-binary-cache", :pre_install) do |installer_context|
6
+ PodPrebuild::PreInstallHook.new(installer_context).run
7
+ end
8
+
9
+ Pod::HooksManager.register("cocoapods-binary-cache", :post_install) do |installer_context|
10
+ PodPrebuild::PostInstallHook.new(installer_context).run
11
+ end
@@ -0,0 +1,12 @@
1
+ # attr_accessor for class variable.
2
+ # usage:
3
+ #
4
+ # ```
5
+ # class Pod
6
+ # class_attr_accessor :is_prebuild_stage
7
+ # end
8
+ # ```
9
+ #
10
+ def class_attr_accessor(symbol)
11
+ self.class.send(:attr_accessor, symbol)
12
+ end
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Boris Bügling <boris@icculus.org>
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,247 @@
1
+ require 'fourflusher'
2
+ require 'xcpretty' # TODO (thuyen): Revise this dependency
3
+
4
+ PLATFORMS = { 'iphonesimulator' => 'iOS',
5
+ 'appletvsimulator' => 'tvOS',
6
+ 'watchsimulator' => 'watchOS' }
7
+
8
+ # Build specific target to framework file
9
+ # @param [PodTarget] target
10
+ # a specific pod target
11
+ #
12
+ def build_for_iosish_platform(sandbox,
13
+ build_dir,
14
+ output_path,
15
+ target,
16
+ configuration,
17
+ device,
18
+ simulator,
19
+ bitcode_enabled,
20
+ custom_build_options = [], # Array<String>
21
+ custom_build_options_simulator = [], # Array<String>
22
+ enable_device_build = false
23
+ )
24
+
25
+ deployment_target = target.platform.deployment_target.to_s
26
+
27
+ target_label = target.label # name with platform if it's used in multiple platforms
28
+ Pod::UI.puts "Prebuilding #{target_label}..."
29
+
30
+ other_options = []
31
+ # bitcode enabled
32
+ other_options += ['BITCODE_GENERATION_MODE=bitcode'] if bitcode_enabled
33
+ # make less arch to iphone simulator for faster build
34
+ custom_build_options_simulator += ['ARCHS=x86_64', 'ONLY_ACTIVE_ARCH=NO'] if simulator == 'iphonesimulator'
35
+
36
+ # paths
37
+ target_name = target.name # equals target.label, like "AFNeworking-iOS" when AFNetworking is used in multiple platforms.
38
+ module_name = target.product_module_name
39
+ device_framework_path = "#{build_dir}/#{configuration}-#{device}/#{target_name}/#{module_name}.framework"
40
+ simulator_framework_path = "#{build_dir}/#{configuration}-#{simulator}/#{target_name}/#{module_name}.framework"
41
+ simulator_target_products_path = "#{build_dir}/#{configuration}-#{simulator}/#{target_name}"
42
+
43
+ if !Dir.exist?(simulator_framework_path)
44
+ is_succeed, = xcodebuild(
45
+ sandbox,
46
+ target_label,
47
+ configuration,
48
+ simulator,
49
+ deployment_target,
50
+ other_options + custom_build_options_simulator
51
+ )
52
+ raise "Build simulator framework failed: #{target_label}" unless is_succeed
53
+ else
54
+ puts "Simulator framework already exist at: #{simulator_framework_path}"
55
+ end
56
+
57
+ unless enable_device_build
58
+ FileUtils.cp_r Dir["#{simulator_target_products_path}/*"], output_path
59
+ return
60
+ end
61
+
62
+ if !Dir.exist?(device_framework_path)
63
+ is_succeed, = xcodebuild(
64
+ sandbox,
65
+ target_label,
66
+ configuration,
67
+ device,
68
+ deployment_target,
69
+ other_options + custom_build_options
70
+ )
71
+ raise "Build device framework failed: #{target_label}" unless is_succeed
72
+ else
73
+ puts "Device framework already exist at: #{device_framework_path}"
74
+ end
75
+
76
+ device_binary = device_framework_path + "/#{module_name}"
77
+ simulator_binary = simulator_framework_path + "/#{module_name}"
78
+ return unless File.file?(device_binary) && File.file?(simulator_binary)
79
+
80
+ # the device_lib path is the final output file path
81
+ # combine the binaries
82
+ tmp_lipoed_binary_path = "#{build_dir}/#{target_name}"
83
+ lipo_log = `lipo -create -output #{tmp_lipoed_binary_path} #{device_binary} #{simulator_binary}`
84
+ puts lipo_log unless File.exist?(tmp_lipoed_binary_path)
85
+ FileUtils.mv tmp_lipoed_binary_path, device_binary, :force => true
86
+
87
+ # collect the swiftmodule file for various archs.
88
+ device_swiftmodule_path = device_framework_path + "/Modules/#{module_name}.swiftmodule"
89
+ simulator_swiftmodule_path = simulator_framework_path + "/Modules/#{module_name}.swiftmodule"
90
+ if File.exist?(device_swiftmodule_path)
91
+ FileUtils.cp_r simulator_swiftmodule_path + "/.", device_swiftmodule_path
92
+ end
93
+
94
+ # combine the generated swift headers
95
+ # (In xcode 10.2, the generated swift headers vary for each archs)
96
+ # https://github.com/leavez/cocoapods-binary/issues/58
97
+ simulator_generated_swift_header_path = simulator_framework_path + "/Headers/#{module_name}-Swift.h"
98
+ device_generated_swift_header_path = device_framework_path + "/Headers/#{module_name}-Swift.h"
99
+ if File.exist? simulator_generated_swift_header_path
100
+ device_header = File.read(device_generated_swift_header_path)
101
+ simulator_header = File.read(simulator_generated_swift_header_path)
102
+ # https://github.com/Carthage/Carthage/issues/2718#issuecomment-473870461
103
+ combined_header_content = %Q{
104
+ #if TARGET_OS_SIMULATOR // merged by cocoapods-binary
105
+
106
+ #{simulator_header}
107
+
108
+ #else // merged by cocoapods-binary
109
+
110
+ #{device_header}
111
+
112
+ #endif // merged by cocoapods-binary
113
+ }
114
+ File.write(device_generated_swift_header_path, combined_header_content.strip)
115
+ end
116
+
117
+ # handle the dSYM files
118
+ device_dsym = "#{device_framework_path}.dSYM"
119
+ if File.exist? device_dsym
120
+ # lipo the simulator dsym
121
+ simulator_dsym = "#{simulator_framework_path}.dSYM"
122
+ if File.exist? simulator_dsym
123
+ tmp_lipoed_binary_path = "#{output_path}/#{module_name}.draft"
124
+ lipo_log = `lipo -create -output #{tmp_lipoed_binary_path} #{device_dsym}/Contents/Resources/DWARF/#{module_name} #{simulator_dsym}/Contents/Resources/DWARF/#{module_name}`
125
+ puts lipo_log unless File.exist?(tmp_lipoed_binary_path)
126
+ FileUtils.mv tmp_lipoed_binary_path, "#{device_framework_path}.dSYM/Contents/Resources/DWARF/#{module_name}", :force => true
127
+ end
128
+ # move
129
+ FileUtils.mv device_dsym, output_path, :force => true
130
+ end
131
+
132
+ # output
133
+ output_path.mkpath unless output_path.exist?
134
+ FileUtils.mv device_framework_path, output_path, :force => true
135
+
136
+ end
137
+
138
+ def xcodebuild(sandbox, target, configuration, sdk='macosx', deployment_target=nil, other_options=[])
139
+ args = %W(-project #{sandbox.project_path.realdirpath} -scheme #{target} -configuration #{configuration} -sdk #{sdk} )
140
+ platform = PLATFORMS[sdk]
141
+ args += Fourflusher::SimControl.new.destination(:oldest, platform, deployment_target) unless platform.nil?
142
+ args += other_options
143
+
144
+ args_str = args.join(" ")
145
+ cmd = "xcodebuild #{args_str} 2>&1"
146
+ puts "xcodebuild command: #{cmd}"
147
+ log = `#{cmd}`
148
+
149
+ exit_code = $?.exitstatus # Process::Status
150
+ is_succeed = (exit_code == 0)
151
+
152
+ if !is_succeed
153
+ begin
154
+ if log.include?('** BUILD FAILED **')
155
+ # use xcpretty to print build log
156
+ # 64 represent command invalid. http://www.manpagez.com/man/3/sysexits/
157
+ printer = XCPretty::Printer.new({:formatter => XCPretty::Simple, :colorize => 'auto'})
158
+ log.each_line do |line|
159
+ printer.pretty_print(line)
160
+ end
161
+ else
162
+ raise "shouldn't be handle by xcpretty"
163
+ end
164
+ rescue
165
+ puts log.red
166
+ end
167
+ end
168
+ [is_succeed, log]
169
+ end
170
+
171
+
172
+
173
+ module Pod
174
+ class Prebuild
175
+
176
+ # Build the frameworks with sandbox and targets
177
+ #
178
+ # @param [String] sandbox_root_path
179
+ # The sandbox root path where the targets project place
180
+ #
181
+ # [PodTarget] target
182
+ # The pod targets to build
183
+ #
184
+ # [Pathname] output_path
185
+ # output path for generated frameworks
186
+ #
187
+ def self.build(sandbox_root_path, target, configuration, output_path, bitcode_enabled = false, custom_build_options=[], custom_build_options_simulator=[])
188
+ return if target.nil?
189
+
190
+ sandbox_root = Pathname(sandbox_root_path)
191
+ sandbox = Pod::Sandbox.new(sandbox_root)
192
+ build_dir = self.build_dir(sandbox_root)
193
+
194
+ # -- build the framework
195
+ case target.platform.name
196
+ when :ios
197
+ build_for_iosish_platform(
198
+ sandbox,
199
+ build_dir,
200
+ output_path,
201
+ target,
202
+ configuration,
203
+ "iphoneos",
204
+ "iphonesimulator",
205
+ bitcode_enabled,
206
+ custom_build_options,
207
+ custom_build_options_simulator
208
+ )
209
+ when :osx
210
+ xcodebuild(
211
+ sandbox,
212
+ target.label,
213
+ configuration,
214
+ "macosx",
215
+ nil,
216
+ custom_build_options
217
+ )
218
+ # when :tvos then build_for_iosish_platform(sandbox, build_dir, target, 'appletvos', 'appletvsimulator')
219
+ when :watchos
220
+ build_for_iosish_platform(
221
+ sandbox,
222
+ build_dir,
223
+ output_path,
224
+ target,
225
+ configuration,
226
+ "watchos",
227
+ "watchsimulator",
228
+ true,
229
+ custom_build_options,
230
+ custom_build_options_simulator
231
+ )
232
+ else raise "Unsupported platform for '#{target.name}': '#{target.platform.name}'" end
233
+
234
+ raise Pod::Informative, "The build directory was not found in the expected location" unless build_dir.directory?
235
+ end
236
+
237
+ def self.remove_build_dir(sandbox_root)
238
+ path = build_dir(sandbox_root)
239
+ path.rmtree if path.exist?
240
+ end
241
+
242
+ def self.build_dir(sandbox_root)
243
+ sandbox_root.parent + "build"
244
+ end
245
+
246
+ end
247
+ end