pod-builder-y 2.3.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 (44) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +19 -0
  3. data/Gemfile +8 -0
  4. data/LICENSE.txt +13 -0
  5. data/README.md +385 -0
  6. data/Rakefile +2 -0
  7. data/bin/console +16 -0
  8. data/bin/setup +8 -0
  9. data/exe/pod_builder_y +406 -0
  10. data/lib/core_ext/string.rb +5 -0
  11. data/lib/pod_builder/analyze.rb +59 -0
  12. data/lib/pod_builder/analyzer.rb +16 -0
  13. data/lib/pod_builder/command.rb +14 -0
  14. data/lib/pod_builder/command/build.rb +228 -0
  15. data/lib/pod_builder/command/build_all.rb +15 -0
  16. data/lib/pod_builder/command/clean.rb +75 -0
  17. data/lib/pod_builder/command/deintegrate.rb +101 -0
  18. data/lib/pod_builder/command/generate_lldbinit.rb +128 -0
  19. data/lib/pod_builder/command/generate_podspec.rb +22 -0
  20. data/lib/pod_builder/command/info.rb +18 -0
  21. data/lib/pod_builder/command/init.rb +148 -0
  22. data/lib/pod_builder/command/install_sources.rb +79 -0
  23. data/lib/pod_builder/command/none.rb +16 -0
  24. data/lib/pod_builder/command/restore_all.rb +33 -0
  25. data/lib/pod_builder/command/switch.rb +224 -0
  26. data/lib/pod_builder/command/sync_podfile.rb +34 -0
  27. data/lib/pod_builder/command/update.rb +43 -0
  28. data/lib/pod_builder/configuration.rb +300 -0
  29. data/lib/pod_builder/core.rb +222 -0
  30. data/lib/pod_builder/info.rb +90 -0
  31. data/lib/pod_builder/install.rb +505 -0
  32. data/lib/pod_builder/licenses.rb +73 -0
  33. data/lib/pod_builder/podfile.rb +700 -0
  34. data/lib/pod_builder/podfile/pre_actions_swizzles.rb +84 -0
  35. data/lib/pod_builder/podfile_cp.rb +99 -0
  36. data/lib/pod_builder/podfile_item.rb +530 -0
  37. data/lib/pod_builder/podspec.rb +269 -0
  38. data/lib/pod_builder/rome/post_install.rb +446 -0
  39. data/lib/pod_builder/rome/pre_install.rb +6 -0
  40. data/lib/pod_builder/templates/build_podfile.template +70 -0
  41. data/lib/pod_builder/templates/build_podspec.template +19 -0
  42. data/lib/pod_builder/version.rb +4 -0
  43. data/pod-builder.gemspec +37 -0
  44. metadata +240 -0
@@ -0,0 +1,269 @@
1
+ # This file contains the logic that generates the .podspec files that are placed
2
+ # along to the prebuild frameworks under PodBuilder/Prebuilt
3
+
4
+ module PodBuilder
5
+ class Podspec
6
+ def self.generate(all_buildable_items, analyzer, install_using_frameworks)
7
+ unless all_buildable_items.count > 0
8
+ return
9
+ end
10
+
11
+ puts "Generating PodBuilder's local podspec".yellow
12
+
13
+ platform = analyzer.instance_variable_get("@result").targets.first.platform
14
+ generate_podspec_from(all_buildable_items, platform, install_using_frameworks)
15
+ end
16
+
17
+ private
18
+
19
+ def self.generate_spec_keys_for(item, name, all_buildable_items, install_using_frameworks)
20
+ podspec = ""
21
+ valid = false
22
+
23
+ slash_count = name.count("/") + 1
24
+ indentation = " " * slash_count
25
+ spec_var = "p#{slash_count}"
26
+
27
+ if spec_var == "p1" && item.default_subspecs.count > 0
28
+ podspec += "#{indentation}#{spec_var}.default_subspecs = '#{item.default_subspecs.join("', '")}'\n"
29
+ end
30
+
31
+ if item.name == name
32
+ if_exists = lambda { |t| File.exist?(PodBuilder::prebuiltpath("#{item.root_name}/#{t}") || "") }
33
+
34
+ vendored_frameworks = item.vendored_frameworks
35
+ if item.default_subspecs.reject { |t| "#{item.root_name}/#{t}" == item.name }.count == 0 && install_using_frameworks
36
+ vendored_frameworks += ["#{item.module_name}.framework", "#{item.module_name}.xcframework"].select(&if_exists)
37
+ end
38
+
39
+ existing_vendored_frameworks = vendored_frameworks.select(&if_exists)
40
+ existing_vendored_frameworks_basename = vendored_frameworks.map { |t| "#{item.root_name}/#{File.basename(t)}" }.select(&if_exists)
41
+ vendored_frameworks = (existing_vendored_frameworks + existing_vendored_frameworks_basename).uniq
42
+
43
+ vendored_libraries = item.vendored_libraries
44
+ existing_vendored_libraries_basename = vendored_libraries.map { |t| "#{item.root_name}/#{File.basename(t)}" }.select(&if_exists)
45
+ vendored_libraries += existing_vendored_libraries_basename
46
+
47
+ if install_using_frameworks
48
+ existing_vendored_libraries = vendored_libraries.map { |t| "#{item.module_name}/#{t}" }.select(&if_exists)
49
+ existing_vendored_libraries_basename = vendored_libraries.map { |t| File.basename(t) }.select(&if_exists)
50
+ vendored_libraries = (existing_vendored_libraries + existing_vendored_libraries_basename).uniq
51
+
52
+ # .a are static libraries and should not be included again in the podspec to prevent duplicated symbols (in the app and in the prebuilt framework)
53
+ vendored_libraries.reject! { |t| t.end_with?(".a") }
54
+
55
+ public_headers = []
56
+ resources = []
57
+ exclude_files = []
58
+ vendored_frameworks.each do |vendored_framework|
59
+ binary_path = Dir.glob(PodBuilder::prebuiltpath("#{item.root_name}/#{vendored_framework}/**/#{File.basename(vendored_framework, ".*")}")).first
60
+
61
+ next if binary_path.nil?
62
+
63
+ is_static = `file '#{binary_path}'`.include?("current ar archive")
64
+ if is_static
65
+ parent_folder = File.expand_path("#{binary_path}/..")
66
+ rel_path = Pathname.new(parent_folder).relative_path_from(Pathname.new(PodBuilder::prebuiltpath(item.root_name))).to_s
67
+
68
+ resources.push("#{rel_path}/*.{nib,bundle,xcasset,strings,png,jpg,tif,tiff,otf,ttf,ttc,plist,json,caf,wav,p12,momd}")
69
+ exclude_files.push("#{rel_path}/Info.plist")
70
+ end
71
+ end
72
+ else
73
+ public_headers = Dir.glob(PodBuilder::prebuiltpath("#{item.root_name}/#{item.root_name}/Headers/**/*.h"))
74
+ vendored_libraries += ["#{item.root_name}/lib#{item.root_name}.a"]
75
+ vendored_libraries = vendored_libraries.select(&if_exists)
76
+
77
+ resources = ["#{item.root_name}/*.{nib,bundle,xcasset,strings,png,jpg,tif,tiff,otf,ttf,ttc,plist,json,caf,wav,p12,momd}"]
78
+
79
+ exclude_files = ["*.modulemap"]
80
+ unless item.swift_version.nil?
81
+ exclude_files += ["Swift Compatibility Header/*", "*.swiftmodule"]
82
+ end
83
+ exclude_files.map! { |t| "#{item.root_name}/#{t}" }
84
+ end
85
+
86
+ entries = lambda { |spec_key, spec_value|
87
+ key = "#{indentation}#{spec_var}.#{spec_key}"
88
+ joined_values = spec_value.map { |t| "#{t}" }.uniq.sort.join("', '")
89
+ "#{key} = '#{joined_values}'\n"
90
+ }
91
+
92
+ if vendored_frameworks.count > 0
93
+ podspec += entries.call("vendored_frameworks", vendored_frameworks)
94
+ end
95
+ if vendored_libraries.count > 0
96
+ podspec += entries.call("vendored_libraries", vendored_libraries)
97
+ end
98
+ if item.frameworks.count > 0
99
+ podspec += entries.call("frameworks", item.frameworks)
100
+ end
101
+ if item.libraries.count > 0
102
+ podspec += entries.call("libraries", item.libraries)
103
+ end
104
+ if resources.count > 0
105
+ podspec += entries.call("resources", resources)
106
+ end
107
+ if exclude_files.count > 0
108
+ podspec += entries.call("exclude_files", exclude_files)
109
+ end
110
+ if public_headers.count > 0
111
+ podspec += "#{indentation}#{spec_var}.public_header_files = '#{item.root_name}/Headers/**/*.h'\n"
112
+ end
113
+ if !item.header_dir.nil? && !install_using_frameworks
114
+ podspec += "#{indentation}#{spec_var}.header_dir = '#{item.header_dir}'\n"
115
+ podspec += "#{indentation}#{spec_var}.header_mappings_dir = '#{item.root_name}/Headers/#{item.header_dir}'\n"
116
+ end
117
+
118
+ if item.xcconfig.keys.count > 0
119
+ xcconfig = Hash.new
120
+ item.xcconfig.each do |k, v|
121
+ unless v != "$(inherited)"
122
+ xcconfig[k] = item.xcconfig[k]
123
+ next
124
+ end
125
+ unless k == "OTHER_LDFLAGS"
126
+ next # For the time being limit to OTHER_LDFLAGS key
127
+ end
128
+
129
+ if podspec_values = item.xcconfig[k]
130
+ podspec_values_arr = podspec_values.split(" ")
131
+ podspec_values_arr.push(v)
132
+ v = podspec_values_arr.join(" ")
133
+ end
134
+
135
+ xcconfig[k] = item.xcconfig[k]
136
+ end
137
+
138
+ if xcconfig.keys.count > 0
139
+ podspec += "#{indentation}#{spec_var}.xcconfig = #{xcconfig.to_s}\n"
140
+ end
141
+ end
142
+ if !install_using_frameworks && spec_var == "p1" && vendored_libraries.map { |t| File.basename(t) }.include?("lib#{item.root_name}.a" )
143
+ module_path_files = Dir.glob(PodBuilder.prebuiltpath("#{item.root_name}/**/#{item.root_name}.modulemap"))
144
+ raise "\n\nToo many module maps found for #{item.root_name}".red if module_path_files.count > 1
145
+
146
+ rel_path = Pathname.new(PodBuilder::prebuiltpath).relative_path_from(Pathname.new(PodBuilder::project_path("Pods"))).to_s
147
+ prebuilt_root_var = "#{item.root_name.upcase.gsub("-", "_")}_PREBUILT_ROOT"
148
+
149
+ static_cfg = Hash.new
150
+ if module_path_file = module_path_files.first
151
+ module_map_rel = module_path_file.gsub(PodBuilder::prebuiltpath("#{item.root_name}/#{item.root_name}/"), "")
152
+ static_cfg = { "SWIFT_INCLUDE_PATHS" => "$(inherited) \"$(#{prebuilt_root_var})/#{item.root_name}/#{item.root_name}\"",
153
+ "OTHER_CFLAGS" => "$(inherited) -fmodule-map-file=\"$(#{prebuilt_root_var})/#{item.root_name}/#{item.root_name}/#{module_map_rel}\"",
154
+ "OTHER_SWIFT_FLAGS" => "$(inherited) -Xcc -fmodule-map-file=\"$(#{prebuilt_root_var})/#{item.root_name}/#{item.root_name}/#{module_map_rel}\""
155
+ }
156
+ end
157
+ static_cfg[prebuilt_root_var] = "$(PODS_ROOT)/#{rel_path}"
158
+
159
+ podspec += "#{indentation}#{spec_var}.xcconfig = #{static_cfg.to_s}\n"
160
+ # This seems to be a viable workaround to https://github.com/CocoaPods/CocoaPods/issues/9559 and https://github.com/CocoaPods/CocoaPods/issues/8454
161
+ podspec += "#{indentation}#{spec_var}.user_target_xcconfig = { \"OTHER_LDFLAGS\" => \"$(inherited) -L\\\"$(#{prebuilt_root_var})/#{item.root_name}/#{item.root_name}\\\" -l\\\"#{item.root_name}\\\"\" }\n"
162
+ end
163
+
164
+ deps = item.dependency_names.sort
165
+ if name == item.root_name
166
+ deps.reject! { |t| t.split("/").first == item.root_name }
167
+ end
168
+
169
+ deps.reject! { |t| t == item.name }
170
+ all_buildable_items_name = all_buildable_items.map(&:name)
171
+ deps.select! { |t| all_buildable_items_name.include?(t) }
172
+
173
+ if deps.count > 0
174
+ if podspec.count("\n") > 1
175
+ podspec += "\n"
176
+ end
177
+ deps.each do |dependency|
178
+ podspec += "#{indentation}#{spec_var}.dependency '#{dependency}'\n"
179
+ end
180
+ end
181
+
182
+ valid = valid || (install_using_frameworks ? vendored_frameworks.count > 0 : vendored_libraries.count > 0)
183
+ end
184
+
185
+ subspec_base = name.split("/").first(slash_count).join("/")
186
+ subspec_items = all_buildable_items.select { |t| t.name.start_with?("#{subspec_base}/") }
187
+
188
+ subspec_names = subspec_items.map { |t| t.name.split("/").drop(slash_count).first }.uniq
189
+ subspec_names.map! { |t| "#{subspec_base}/#{t}" }
190
+
191
+ subspec_names.each do |subspec|
192
+ subspec_item = all_buildable_items.detect { |t| t.name == subspec } || item
193
+
194
+ if podspec.length > 0
195
+ podspec += "\n"
196
+ end
197
+
198
+ subspec_keys, subspec_valid = generate_spec_keys_for(subspec_item, subspec, all_buildable_items, install_using_frameworks)
199
+ valid = valid || subspec_valid
200
+
201
+ if subspec_keys.length > 0
202
+ podspec += "#{indentation}#{spec_var}.subspec '#{subspec.split("/").last}' do |p#{slash_count + 1}|\n"
203
+ podspec += subspec_keys
204
+ podspec += "#{indentation}end\n"
205
+ end
206
+ end
207
+
208
+ return podspec, valid
209
+ end
210
+
211
+ def self.generate_podspec_from(all_buildable_items, platform, install_using_frameworks)
212
+ prebuilt_podspec_path = all_buildable_items.map(&:prebuilt_podspec_path)
213
+ prebuilt_podspec_path.each do |path|
214
+ if File.exist?(path)
215
+ FileUtils.rm(path)
216
+ end
217
+ end
218
+
219
+ all_buildable_items.each do |item|
220
+ if item.is_prebuilt
221
+ next
222
+ end
223
+
224
+ if item.name != item.root_name
225
+ if all_buildable_items.map(&:name).include?(item.root_name)
226
+ next # will process root spec, skip subspecs
227
+ end
228
+ end
229
+ if File.exist?(item.prebuilt_podspec_path)
230
+ next # skip if podspec was already generated
231
+ end
232
+
233
+ podspec = "Pod::Spec.new do |p1|\n"
234
+
235
+ podspec += " p1.name = '#{item.root_name}'\n"
236
+ podspec += " p1.version = '#{item.version}'\n"
237
+ podspec += " p1.summary = '#{item.summary.gsub("'", "\\'")}'\n"
238
+ podspec += " p1.homepage = '#{item.homepage}'\n"
239
+ podspec += " p1.author = 'PodBuilder'\n"
240
+ podspec += " p1.source = { 'git' => '#{item.source['git']}'}\n"
241
+ podspec += " p1.license = { :type => '#{item.license}' }\n"
242
+
243
+ podspec += "\n"
244
+ podspec += " p1.#{platform.safe_string_name.downcase}.deployment_target = '#{platform.deployment_target.version}'\n"
245
+ podspec += "\n"
246
+
247
+ main_keys, valid = generate_spec_keys_for(item, item.root_name, all_buildable_items, install_using_frameworks)
248
+ if !valid
249
+ next
250
+ end
251
+
252
+ podspec += main_keys
253
+ podspec += "end"
254
+
255
+ spec_path = item.prebuilt_podspec_path
256
+ if File.directory?(File.dirname(spec_path))
257
+ File.write(spec_path, podspec)
258
+ else
259
+ message = "Prebuilt podspec destination not found for #{File.basename(spec_path)}".red
260
+ if ENV['DEBUGGING']
261
+ puts message
262
+ else
263
+ raise message
264
+ end
265
+ end
266
+ end
267
+ end
268
+ end
269
+ end
@@ -0,0 +1,446 @@
1
+ require 'fourflusher'
2
+ require 'colored'
3
+ require 'pathname'
4
+
5
+ module PodBuilder
6
+ class XcodeBuildSettings
7
+ attr_reader :platform_name
8
+ attr_reader :build_destination
9
+
10
+ def initialize(platform_name)
11
+ @platform_name = platform_name
12
+
13
+ case platform_name
14
+ when "iphoneos" then @build_destination = "generic/platform=iOS"
15
+ when "iphonesimulator" then @build_destination = "generic/platform=iOS Simulator"
16
+ when "catalyst" then @build_destination = "platform=macOS,arch=x86_64,variant=Mac Catalyst"
17
+ when "macos" then @build_destination = "generic/platform=OS X"
18
+ when "tvos" then @build_destination = "generic/platform=tvOS"
19
+ when "tvossimulator" then @build_destination = "generic/platform=tvOS Simulator"
20
+ when "watchos" then @build_destination = "generic/platform=watchOS"
21
+ when "watchossimulator" then @build_destination = "generic/platform=watchOS Simulator"
22
+ else raise "\n\nUnknown platform '#{platform_name}'".red end
23
+ end
24
+ end
25
+
26
+ def self.build_for_iosish_platform_framework(sandbox, build_dir, target, device, simulator, configuration, deterministic_build)
27
+ dsym_device_folder = File.join(build_dir, "dSYM", device)
28
+ dsym_simulator_folder = File.join(build_dir, "dSYM", simulator)
29
+ FileUtils.mkdir_p(dsym_device_folder)
30
+ FileUtils.mkdir_p(dsym_simulator_folder)
31
+
32
+ deployment_target = target.platform_deployment_target
33
+ target_label = target.cocoapods_target_label
34
+
35
+ xcodebuild(sandbox, target_label, device, deployment_target, configuration, deterministic_build, [], {})
36
+ excluded_archs = ["i386"] # Fixes https://github.com/Subito-it/PodBuilder/issues/17
37
+ excluded_archs += ["arm64"] # Exclude apple silicon slice
38
+ xcodebuild(sandbox, target_label, simulator, deployment_target, configuration, deterministic_build, excluded_archs, {})
39
+
40
+ spec_names = target.specs.map { |spec| [spec.root.name, spec.root.module_name] }.uniq
41
+ spec_names.each do |root_name, module_name|
42
+ device_base = "#{build_dir}/#{configuration}-#{device}/#{root_name}"
43
+ device_lib = "#{device_base}/#{module_name}.framework/#{module_name}"
44
+ device_dsym = "#{device_base}/#{module_name}.framework.dSYM"
45
+ device_framework_lib = File.dirname(device_lib)
46
+ device_swift_header_path = "#{device_framework_lib}/Headers/#{module_name}-Swift.h"
47
+
48
+ simulator_base = "#{build_dir}/#{configuration}-#{simulator}/#{root_name}"
49
+ simulator_lib = "#{simulator_base}/#{module_name}.framework/#{module_name}"
50
+ simulator_dsym = "#{simulator_base}/#{module_name}.framework.dSYM"
51
+ simulator_framework_lib = File.dirname(simulator_lib)
52
+ simulator_swift_header_path = "#{simulator_framework_lib}/Headers/#{module_name}-Swift.h"
53
+
54
+ next unless File.file?(device_lib) && File.file?(simulator_lib)
55
+
56
+ # Starting with Xcode 12b3 the simulator binary contains an arm64 slice as well which conflict with the one in the device_lib
57
+ # when creating the fat library. A naive workaround is to remove the arm64 from the simulator_lib however this is wrong because
58
+ # we might actually need to have 2 separated arm64 slices, one for simulator and one for device each built with different
59
+ # compile time directives (e.g #if targetEnvironment(simulator))
60
+ #
61
+ # For the time being we remove the arm64 slice bacause otherwise the `xcrun lipo -create -output ...` would fail.
62
+ if `xcrun lipo -info #{simulator_lib}`.include?("arm64")
63
+ `xcrun lipo -remove arm64 #{simulator_lib} -o #{simulator_lib}`
64
+ end
65
+
66
+ raise "Lipo failed on #{device_lib}" unless system("xcrun lipo -create -output #{device_lib} #{device_lib} #{simulator_lib}")
67
+
68
+ merge_header_into(device_swift_header_path, simulator_swift_header_path)
69
+
70
+ # Merge device framework into simulator framework (so that e.g swift Module folder is merged)
71
+ # letting device framework files overwrite simulator ones
72
+ FileUtils.cp_r(File.join(device_framework_lib, "."), simulator_framework_lib)
73
+ source_lib = File.dirname(simulator_framework_lib)
74
+
75
+ FileUtils.mv(device_dsym, dsym_device_folder) if File.exist?(device_dsym)
76
+ FileUtils.mv(simulator_dsym, dsym_simulator_folder) if File.exist?(simulator_dsym)
77
+
78
+ FileUtils.mv(source_lib, build_dir)
79
+
80
+ # Remove frameworks leaving dSYMs
81
+ FileUtils.rm_rf(device_framework_lib)
82
+ FileUtils.rm_rf(simulator_framework_lib)
83
+ end
84
+ end
85
+
86
+ def self.build_for_iosish_platform_lib(sandbox, build_dir, target, device, simulator, configuration, deterministic_build, prebuilt_root_paths)
87
+ deployment_target = target.platform_deployment_target
88
+ target_label = target.cocoapods_target_label
89
+
90
+ spec_names = target.specs.map { |spec| [spec.root.name, spec.root.module_name] }.uniq
91
+
92
+ xcodebuild(sandbox, target_label, device, deployment_target, configuration, deterministic_build, [], prebuilt_root_paths)
93
+ excluded_archs = ["arm64"] # Exclude Apple silicon slice
94
+ xcodebuild(sandbox, target_label, simulator, deployment_target, configuration, deterministic_build, excluded_archs, prebuilt_root_paths)
95
+
96
+ spec_names.each do |root_name, module_name|
97
+ simulator_base = "#{build_dir}/#{configuration}-#{simulator}/#{root_name}"
98
+ simulator_lib = "#{simulator_base}/lib#{root_name}.a"
99
+
100
+ device_base = "#{build_dir}/#{configuration}-#{device}/#{root_name}"
101
+ device_lib = "#{device_base}/lib#{root_name}.a"
102
+
103
+ unless File.file?(device_lib) && File.file?(simulator_lib)
104
+ next
105
+ end
106
+
107
+ # Starting with Xcode 12b3 the simulator binary contains an arm64 slice as well which conflict with the one in the device_lib
108
+ # when creating the fat library. A naive workaround is to remove the arm64 from the simulator_lib however this is wrong because
109
+ # we might actually need to have 2 separated arm64 slices, one for simulator and one for device each built with different
110
+ # compile time directives (e.g #if targetEnvironment(simulator))
111
+ #
112
+ # For the time being we remove the arm64 slice bacause otherwise the `xcrun lipo -create -output ...` would fail.
113
+ if `xcrun lipo -info #{simulator_lib}`.include?("arm64")
114
+ `xcrun lipo -remove arm64 #{simulator_lib} -o #{simulator_lib}`
115
+ end
116
+
117
+ raise "Lipo failed on #{device_lib}" unless system("xcrun lipo -create -output #{device_lib} #{device_lib} #{simulator_lib}")
118
+
119
+ device_headers = Dir.glob("#{device_base}/**/*.h")
120
+ simulator_headers = Dir.glob("#{simulator_base}/**/*.h")
121
+ device_headers.each do |device_path|
122
+ simulator_path = device_path.gsub(device_base, simulator_base)
123
+
124
+ merge_header_into(device_path, simulator_path)
125
+ end
126
+ simulator_only_headers = simulator_headers - device_headers.map { |t| t.gsub(device_base, simulator_base) }
127
+ simulator_only_headers.each do |path|
128
+ add_simulator_conditional(path)
129
+ dir_name = File.dirname(path)
130
+ destination_folder = dir_name.gsub(simulator_base, device_base)
131
+ FileUtils.mkdir_p(destination_folder)
132
+ FileUtils.cp(path, destination_folder)
133
+ end
134
+
135
+ swiftmodule_path = "#{simulator_base}/#{root_name}.swiftmodule"
136
+ if File.directory?(swiftmodule_path)
137
+ FileUtils.cp_r("#{swiftmodule_path}/.", "#{device_base}/#{root_name}.swiftmodule")
138
+ end
139
+
140
+ if File.exist?("#{device_base}/#{root_name}.swiftmodule")
141
+ # This is a swift pod with a swiftmodule in the root of the prebuilt folder
142
+ else
143
+ # Objective-C pods have the swiftmodule generated under Pods/Headers/Public
144
+ public_headers_path = "#{Configuration.build_path}/Pods/Headers/Public/#{root_name}"
145
+ module_public_headers_path = "#{Configuration.build_path}/Pods/Headers/Public/#{module_name}"
146
+ if public_headers_path.downcase != module_public_headers_path.downcase && File.directory?(public_headers_path) && File.directory?(module_public_headers_path)
147
+ # For pods with module_name != name we have to move the modulemap files to the root_name one
148
+ module_public_headers_path = "#{Configuration.build_path}/Pods/Headers/Public/#{module_name}"
149
+ FileUtils.cp_r("#{module_public_headers_path}/.", public_headers_path, :remove_destination => true)
150
+ end
151
+ Dir.glob("#{public_headers_path}/**/*.*").each do |path|
152
+ destination_folder = "#{device_base}/Headers" + path.gsub(public_headers_path, "")
153
+ destination_folder = File.dirname(destination_folder)
154
+ FileUtils.mkdir_p(destination_folder)
155
+ FileUtils.cp(path, destination_folder)
156
+ end
157
+ end
158
+
159
+ destination_path = "#{build_dir}/#{root_name}"
160
+ if Dir.glob("#{device_base}/**/*.{a,framework,h}").count > 0
161
+ FileUtils.mv(device_base, destination_path)
162
+
163
+ module_maps = Dir.glob("#{destination_path}/**/*.modulemap")
164
+ module_map_device_base = device_base.gsub(/^\/private/, "") + "/"
165
+ module_maps.each do |module_map|
166
+ content = File.read(module_map)
167
+ content.gsub!(module_map_device_base, "")
168
+ File.write(module_map, content)
169
+ end
170
+ end
171
+ end
172
+ end
173
+
174
+ def self.merge_header_into(device_file, simulator_file)
175
+ unless File.exist?(device_file) || File.exist?(simulator_file)
176
+ return
177
+ end
178
+
179
+ device_content = File.file?(device_file) ? File.read(device_file) : ""
180
+ simulator_content = File.file?(simulator_file) ? File.read(simulator_file) : ""
181
+ merged_content = %{
182
+ #if TARGET_OS_SIMULATOR
183
+ // ->
184
+
185
+ #{simulator_content}
186
+
187
+ // ->
188
+ #else
189
+ // ->
190
+
191
+ #{device_content}
192
+
193
+ // ->
194
+ #endif
195
+ }
196
+ File.write(device_file, merged_content)
197
+ end
198
+
199
+ def self.add_simulator_conditional(path)
200
+ file_content = File.read(path)
201
+ content = %{
202
+ #if TARGET_OS_SIMULATOR
203
+ #{file_content}
204
+ #endif
205
+ }
206
+ File.write(path, content)
207
+ end
208
+
209
+ def self.xcodebuild(sandbox, target, sdk='macosx', deployment_target=nil, configuration, deterministic_build, exclude_archs, prebuilt_root_paths)
210
+ args = %W(-project #{sandbox.project_path.realdirpath} -scheme #{target} -configuration #{configuration} -sdk #{sdk})
211
+ supported_platforms = { 'iphonesimulator' => 'iOS', 'appletvsimulator' => 'tvOS', 'watchsimulator' => 'watchOS' }
212
+ if platform = supported_platforms[sdk]
213
+ args += Fourflusher::SimControl.new.destination(:oldest, platform, deployment_target) unless platform.nil?
214
+ end
215
+
216
+ xcodebuild_version = `xcodebuild -version | head -n1 | awk '{print $2}'`.strip().to_f
217
+ if exclude_archs.count > 0 && xcodebuild_version >= 12.0
218
+ args += ["EXCLUDED_ARCHS=#{exclude_archs.join(" ")}"]
219
+ end
220
+ prebuilt_root_paths.each do |k, v|
221
+ args += ["#{k.upcase.gsub("-", "_")}_PREBUILT_ROOT=#{v.gsub(/ /, '\ ')}"]
222
+ end
223
+
224
+ environmental_variables = {}
225
+ if deterministic_build
226
+ environmental_variables["ZERO_AR_DATE"] = "1"
227
+ end
228
+
229
+ execute_command 'xcodebuild', args, true, environmental_variables
230
+ end
231
+
232
+ # Copy paste implementation from CocoaPods internals to be able to call poopen3 passing environmental variables
233
+ def self.execute_command(executable, command, raise_on_failure = true, environmental_variables = {})
234
+ bin = Pod::Executable.which!(executable)
235
+
236
+ command = command.map(&:to_s)
237
+ full_command = "#{bin} #{command.join(' ')}"
238
+
239
+ stdout = Pod::Executable::Indenter.new
240
+ stderr = Pod::Executable::Indenter.new
241
+
242
+ status = popen3(bin, command, stdout, stderr, environmental_variables)
243
+ stdout = stdout.join
244
+ stderr = stderr.join
245
+ output = stdout + stderr
246
+ unless status.success?
247
+ if raise_on_failure
248
+ raise "#{full_command}\n\n#{output}"
249
+ else
250
+ UI.message("[!] Failed: #{full_command}".red)
251
+ end
252
+ end
253
+
254
+ output
255
+ end
256
+
257
+ def self.popen3(bin, command, stdout, stderr, environmental_variables)
258
+ require 'open3'
259
+ Open3.popen3(environmental_variables, bin, *command) do |i, o, e, t|
260
+ Pod::Executable::reader(o, stdout)
261
+ Pod::Executable::reader(e, stderr)
262
+ i.close
263
+
264
+ status = t.value
265
+
266
+ o.flush
267
+ e.flush
268
+ sleep(0.01)
269
+
270
+ status
271
+ end
272
+ end
273
+
274
+ def self.enable_debug_information(project_path, configuration)
275
+ project = Xcodeproj::Project.open(project_path)
276
+ project.targets.each do |target|
277
+ config = target.build_configurations.find { |config| config.name.eql? configuration }
278
+ config.build_settings["DEBUG_INFORMATION_FORMAT"] = "dwarf-with-dsym"
279
+ config.build_settings["ONLY_ACTIVE_ARCH"] = "NO"
280
+ end
281
+ project.save
282
+ end
283
+ end
284
+
285
+ Pod::HooksManager.register('podbuilder-rome', :post_install) do |installer_context, user_options|
286
+ enable_dsym = user_options.fetch('dsym', true)
287
+ configuration = user_options.fetch('configuration', 'Debug')
288
+ uses_frameworks = user_options.fetch('uses_frameworks', true)
289
+ if user_options["pre_compile"]
290
+ user_options["pre_compile"].call(installer_context)
291
+ end
292
+ build_catalyst = user_options.fetch('build_catalyst', false)
293
+ build_xcframeworks = user_options.fetch('build_xcframeworks', false)
294
+
295
+ prebuilt_root_paths = JSON.parse(user_options["prebuilt_root_paths"].gsub('=>', ':'))
296
+
297
+ sandbox_root = Pathname(installer_context.sandbox_root)
298
+ sandbox = Pod::Sandbox.new(sandbox_root)
299
+
300
+ PodBuilder::enable_debug_information(sandbox.project_path, configuration)
301
+
302
+ build_dir = sandbox_root.parent + 'build'
303
+ base_destination = sandbox_root.parent + 'Prebuilt'
304
+
305
+ build_dir.rmtree if build_dir.directory?
306
+
307
+ targets = installer_context.umbrella_targets.select { |t| t.specs.any? }
308
+ raise "\n\nUnsupported target count".red unless targets.count == 1
309
+ target = targets.first
310
+
311
+ if build_xcframeworks
312
+ project_path = sandbox_root.parent + 'Pods/Pods.xcodeproj'
313
+
314
+ case target.platform_name
315
+ when :ios then
316
+ xcodebuild_settings = [PodBuilder::XcodeBuildSettings.new("iphoneos"), PodBuilder::XcodeBuildSettings.new("iphonesimulator")]
317
+ if build_catalyst
318
+ xcodebuild_settings += [PodBuilder::XcodeBuildSettings.new("catalyst")]
319
+ end
320
+ when :osx then xcodebuild_settings = [PodBuilder::XcodeBuildSettings.new("macos")]
321
+ when :tvos then xcodebuild_settings = [PodBuilder::XcodeBuildSettings.new("tvos"), PodBuilder::XcodeBuildSettings.new("tvossimulator")]
322
+ when :watchos then xcodebuild_settings = [PodBuilder::XcodeBuildSettings.new("watchos"), PodBuilder::XcodeBuildSettings.new("watchossimulator")]
323
+ else raise "\n\nUnknown platform '#{target.platform_name}'".red end
324
+
325
+ xcodebuild_settings.each do |xcodebuild_setting|
326
+ puts "Building xcframeworks for #{xcodebuild_setting.platform_name}".yellow
327
+ raise "\n\n#{build_destination} xcframework archive failed!".red if !system("xcodebuild archive -project #{project_path.to_s} -scheme Pods-DummyTarget -destination '#{xcodebuild_setting.build_destination}' -archivePath '#{build_dir}/#{xcodebuild_setting.platform_name}' SKIP_INSTALL=NO > /dev/null 2>&1")
328
+ end
329
+
330
+ built_items = Dir.glob("#{build_dir}/#{xcodebuild_settings[0].platform_name}.xcarchive/Products/Library/Frameworks/*").reject { |t| File.basename(t, ".*") == "Pods_DummyTarget" }
331
+
332
+ built_items.each do |built_item|
333
+ built_item_paths = [built_item]
334
+ xcodebuild_settings.drop(1).each do |xcodebuild_setting|
335
+ path = "#{build_dir}/#{xcodebuild_setting.platform_name}.xcarchive/Products/Library/Frameworks/#{File.basename(built_item)}"
336
+ if File.directory?(path)
337
+ built_item_paths.push(path)
338
+ else
339
+ built_item_paths = []
340
+ break
341
+ end
342
+ end
343
+
344
+ next if built_item_paths.count == 0
345
+
346
+ framework_name = File.basename(built_item_paths.first, ".*")
347
+ xcframework_path = "#{base_destination}/#{framework_name}/#{framework_name}.xcframework"
348
+ framework_params = built_item_paths.map { |t| "-framework '#{t}'"}.join(" ")
349
+ raise "\n\nFailed packing xcframework!".red if !system("xcodebuild -create-xcframework #{framework_params} -output '#{xcframework_path}' > /dev/null 2>&1")
350
+
351
+ if enable_dsym
352
+ xcodebuild_settings.each do |xcodebuild_setting|
353
+ dsym_source = "#{build_dir}/#{xcodebuild_setting.platform_name}.xcarchive/dSYMs/"
354
+ if File.directory?(dsym_source)
355
+ destination = sandbox_root.parent + "dSYMs"
356
+ FileUtils.mkdir_p(destination)
357
+ FileUtils.mv(dsym_source, destination)
358
+ FileUtils.mv("#{destination}/dSYMs", "#{destination}/#{xcodebuild_setting.platform_name}")
359
+ end
360
+ end
361
+ else
362
+ raise "Not implemented"
363
+ end
364
+ end
365
+
366
+ built_count = built_items.count
367
+ Pod::UI.puts "Built #{built_count} #{'item'.pluralize(built_count)}"
368
+ else
369
+ case [target.platform_name, uses_frameworks]
370
+ when [:ios, true] then PodBuilder::build_for_iosish_platform_framework(sandbox, build_dir, target, 'iphoneos', 'iphonesimulator', configuration, PodBuilder::Configuration.deterministic_build)
371
+ when [:osx, true] then PodBuilder::xcodebuild(sandbox, target.cocoapods_target_label, configuration, PodBuilder::Configuration.deterministic_build, {})
372
+ when [:tvos, true] then PodBuilder::build_for_iosish_platform_framework(sandbox, build_dir, target, 'appletvos', 'appletvsimulator', configuration, PodBuilder::Configuration.deterministic_build)
373
+ when [:watchos, true] then PodBuilder::build_for_iosish_platform_framework(sandbox, build_dir, target, 'watchos', 'watchsimulator', configuration, PodBuilder::Configuration.deterministic_build)
374
+ when [:ios, false] then PodBuilder::build_for_iosish_platform_lib(sandbox, build_dir, target, 'iphoneos', 'iphonesimulator', configuration, PodBuilder::Configuration.deterministic_build, prebuilt_root_paths)
375
+ when [:osx, false] then PodBuilder::xcodebuild(sandbox, target.cocoapods_target_label, configuration, PodBuilder::Configuration.deterministic_build, prebuilt_root_paths)
376
+ when [:tvos, false] then PodBuilder::build_for_iosish_platform_lib(sandbox, build_dir, target, 'appletvos', 'appletvsimulator', configuration, PodBuilder::Configuration.deterministic_build, prebuilt_root_paths)
377
+ when [:watchos, false] then PodBuilder::build_for_iosish_platform_lib(sandbox, build_dir, target, 'watchos', 'watchsimulator', configuration, PodBuilder::Configuration.deterministic_build, prebuilt_root_paths)
378
+ else raise "\n\nUnknown platform '#{target.platform_name}'".red end
379
+
380
+ raise Pod::Informative, 'The build directory was not found in the expected location.' unless build_dir.directory?
381
+
382
+ specs = installer_context.umbrella_targets.map { |t| t.specs.map(&:name) }.flatten.map { |t| t.split("/").first }.uniq
383
+ built_count = Dir["#{build_dir}/*"].select { |t| specs.include?(File.basename(t)) }.count
384
+ Pod::UI.puts "Built #{built_count} #{'item'.pluralize(built_count)}, copying..."
385
+
386
+ base_destination.rmtree if base_destination.directory?
387
+
388
+ installer_context.umbrella_targets.each do |umbrella|
389
+ umbrella.specs.each do |spec|
390
+ root_name = spec.name.split("/").first
391
+
392
+ if uses_frameworks
393
+ destination = File.join(base_destination, root_name)
394
+ else
395
+ destination = File.join(base_destination, root_name, root_name)
396
+ end
397
+ # Make sure the device target overwrites anything in the simulator build, otherwise iTunesConnect
398
+ # can get upset about Info.plist containing references to the simulator SDK
399
+ files = Pathname.glob("build/#{root_name}/*").reject { |f| f.to_s =~ /Pods[^.]+\.framework/ }
400
+
401
+ consumer = spec.consumer(umbrella.platform_name)
402
+ file_accessor = Pod::Sandbox::FileAccessor.new(sandbox.pod_dir(spec.root.name), consumer)
403
+ files += file_accessor.vendored_libraries
404
+ files += file_accessor.vendored_frameworks
405
+ files += file_accessor.resources
406
+
407
+ FileUtils.mkdir_p(destination)
408
+ files.each do |file|
409
+ FileUtils.cp_r(file, destination)
410
+ end
411
+ end
412
+ end
413
+
414
+ # Depending on the resource it may happen that it is present twice, both in the .framework and in the parent folder
415
+ Dir.glob("#{base_destination}/*") do |path|
416
+ unless File.directory?(path)
417
+ return
418
+ end
419
+
420
+ files = Dir.glob("#{path}/*")
421
+ framework_files = Dir.glob("#{path}/*.framework/**/*").map { |t| File.basename(t) }
422
+
423
+ files.each do |file|
424
+ filename = File.basename(file.gsub(/\.xib$/, ".nib"))
425
+ if framework_files.include?(filename)
426
+ FileUtils.rm_rf(file)
427
+ end
428
+ end
429
+ end
430
+
431
+ if enable_dsym
432
+ dsym_source = "#{build_dir}/dSYM"
433
+ if File.directory?(dsym_source)
434
+ FileUtils.mv(dsym_source, sandbox_root.parent)
435
+ end
436
+ else
437
+ raise "Not implemented"
438
+ end
439
+ end
440
+
441
+ build_dir.rmtree if build_dir.directory?
442
+
443
+ if user_options["post_compile"]
444
+ user_options["post_compile"].call(installer_context)
445
+ end
446
+ end