cocoapods-binary-cache 0.1.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.
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