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,73 @@
1
+ module PodBuilder
2
+ class Licenses
3
+ def self.write(licenses, all_buildable_items)
4
+ puts "Writing licenses".yellow
5
+ license_file_path = PodBuilder::project_path(Configuration.license_filename) + ".plist"
6
+
7
+ current_licenses = []
8
+ if File.exist?(license_file_path)
9
+ plist = CFPropertyList::List.new(:file => license_file_path)
10
+ dict = CFPropertyList.native_types(plist.value)
11
+ current_licenses = dict["PreferenceSpecifiers"]
12
+
13
+ if current_licenses.count > 0
14
+ licenses_header = current_licenses.shift
15
+ raise "\n\nUnexpected license found in header".red if licenses_header.has_key?("License")
16
+ end
17
+ if current_licenses.count > 0
18
+ license_footer = current_licenses.pop
19
+ raise "\n\nUnexpected license found in footer".red if license_footer.has_key?("License")
20
+ end
21
+ end
22
+
23
+ if licenses.count > 0
24
+ licenses_header = licenses.shift
25
+ raise "\n\nUnexpected license found in header".red if licenses_header.has_key?("License")
26
+ license_footer = licenses.pop
27
+ raise "\n\nUnexpected license found in footer".red if license_footer.has_key?("License")
28
+
29
+ lincenses_titles = licenses.map { |x| x["Title"] }
30
+ current_licenses.select! { |x| !lincenses_titles.include?(x["Title"]) }
31
+ end
32
+
33
+ licenses += current_licenses # merge with existing license
34
+ licenses.uniq! { |x| x["Title"] }
35
+ licenses.sort_by! { |x| x["Title"] }
36
+ licenses.select! { |x| !Configuration.skip_licenses.include?(x["Title"]) }
37
+ licenses.select! { |x| all_buildable_items.map(&:root_name).include?(x["Title"]) } # Remove items that are no longer included
38
+
39
+ license_dict = {}
40
+ license_dict["PreferenceSpecifiers"] = [licenses_header, licenses, license_footer].compact.flatten
41
+ license_dict["StringsTable"] = "Acknowledgements"
42
+ license_dict["Title"] = license_dict["StringsTable"]
43
+
44
+ plist = CFPropertyList::List.new
45
+ plist.value = CFPropertyList.guess(license_dict)
46
+ plist.save(license_file_path, CFPropertyList::List::FORMAT_BINARY)
47
+
48
+ if licenses.count > 0
49
+ write_markdown(license_file_path)
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ def self.write_markdown(plist_path)
56
+ plist = CFPropertyList::List.new(:file => plist_path)
57
+ dict = CFPropertyList.native_types(plist.value)
58
+ licenses = dict["PreferenceSpecifiers"]
59
+
60
+ header = licenses.shift
61
+
62
+ markdown = []
63
+ markdown += ["# #{header["Title"]}", header["FooterText"], ""]
64
+ markdown += licenses.map { |x| ["## #{x["Title"]}", x["FooterText"], ""] }
65
+
66
+ markdown.flatten!
67
+
68
+ markdown_path = plist_path.chomp(File.extname(plist_path)) + ".md"
69
+
70
+ File.write(markdown_path, markdown.join("\n"))
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,700 @@
1
+ require 'json'
2
+ module PodBuilder
3
+ class Podfile
4
+ PODBUILDER_LOCK_ACTION = ["raise \"\\n🚨 Do not launch 'pod install' manually, use `pod_builder` instead!\\n\" if !File.exist?('pod_builder.lock')"].freeze
5
+
6
+ PRE_INSTALL_ACTIONS = ["Pod::Installer::Xcode::TargetValidator.send(:define_method, :verify_no_duplicate_framework_and_library_names) {}", "require 'pod_builder/podfile/pre_actions_swizzles'"].freeze
7
+
8
+ def self.from_podfile_items(items, analyzer, build_configuration, install_using_frameworks, build_catalyst, build_xcframeworks)
9
+ raise "\n\nno items".red unless items.count > 0
10
+
11
+ sources = analyzer.sources
12
+
13
+ cwd = File.dirname(File.expand_path(__FILE__))
14
+ podfile = File.read("#{cwd}/templates/build_podfile.template")
15
+
16
+ platform = analyzer.instance_variable_get("@result").targets.first.platform
17
+
18
+ podfile.sub!("%%%use_frameworks%%%", install_using_frameworks ? "use_frameworks!" : "")
19
+ podfile.sub!("%%%uses_frameworks%%%", install_using_frameworks ? "true" : "false")
20
+ podfile.sub!("%%%build_xcframeworks%%%", build_xcframeworks ? "true" : "false")
21
+ podfile.sub!("%%%build_catalyst%%%", build_catalyst ? "true" : "false")
22
+
23
+ podfile.sub!("%%%platform_name%%%", platform.name.to_s)
24
+ podfile.sub!("%%%deployment_version%%%", platform.deployment_target.version)
25
+
26
+ podfile.sub!("%%%sources%%%", sources.map { |x| "source '#{x.url}'" }.join("\n"))
27
+
28
+ podfile.sub!("%%%build_configuration%%%", build_configuration.capitalize)
29
+
30
+ podfile_build_settings = ""
31
+
32
+ pod_dependencies = {}
33
+
34
+ items.each do |item|
35
+ build_settings = Configuration.build_settings.dup
36
+
37
+ item_build_settings = Configuration.build_settings_overrides[item.name] || {}
38
+
39
+ # These settings need to be set as is to properly build frameworks
40
+ build_settings["SWIFT_COMPILATION_MODE"] = "wholemodule"
41
+ build_settings["ONLY_ACTIVE_ARCH"] = "NO"
42
+ build_settings["DEBUG_INFORMATION_FORMAT"] = "dwarf-with-dsym"
43
+
44
+ # https://thi.imhttps://thi.im/posts/swift-serialize-debugging-options/
45
+ build_settings["SWIFT_SERIALIZE_DEBUGGING_OPTIONS"] = "NO"
46
+
47
+ build_settings["IPHONEOS_DEPLOYMENT_TARGET"] = platform.deployment_target.version # Fix compilation warnings on Xcode 12
48
+
49
+ # Don't store .pcm info in binary, see https://forums.swift.org/t/swift-behavior-of-gmodules-and-dsyms/23211/3
50
+ build_settings["CLANG_ENABLE_MODULE_DEBUGGING"] = "NO"
51
+ build_settings["OTHER_SWIFT_FLAGS"] = "$(inherited) -Xfrontend -no-clang-module-breadcrumbs"
52
+
53
+ # Ignore deprecation warnings
54
+ build_settings["GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS"] = "NO"
55
+
56
+ # Improve compile speed
57
+ build_settings["COMPILER_INDEX_STORE_ENABLE"] = "NO"
58
+ build_settings["SWIFT_INDEX_STORE_ENABLE"] = "NO"
59
+ build_settings["MTL_ENABLE_INDEX_STORE"] = "NO"
60
+
61
+ if Configuration.build_system == "Legacy"
62
+ build_settings["BUILD_LIBRARY_FOR_DISTRIBUTION"] = "NO"
63
+ raise "\n\nCan't enable library evolution support with legacy build system!".red if Configuration.library_evolution_support
64
+ elsif Configuration.library_evolution_support
65
+ build_settings["BUILD_LIBRARY_FOR_DISTRIBUTION"] = "YES"
66
+ end
67
+ if Configuration.build_xcframeworks
68
+ build_settings["BUILD_LIBRARY_FOR_DISTRIBUTION"] = "YES"
69
+ end
70
+
71
+ build_settings["SWIFT_VERSION"] = item_build_settings["SWIFT_VERSION"] || item.swift_version || project_swift_version(analyzer)
72
+
73
+ if build_settings["ENABLE_BITCODE"] == "YES"
74
+ build_settings["BITCODE_GENERATION_MODE"] = "bitcode"
75
+ end
76
+
77
+ item_build_settings.each do |k, v|
78
+ build_settings[k] = v
79
+ end
80
+
81
+ podfile_build_settings += "set_build_settings(\"#{item.root_name}\", #{build_settings.to_s}, installer)\n "
82
+
83
+ dependency_names = item.dependency_names.map { |x|
84
+ if x.split("/").first == item.root_name
85
+ next nil # remove dependency to parent spec
86
+ end
87
+ if overridded_module_name = Configuration.spec_overrides.fetch(x, {})["module_name"] # this might no longer be needed after
88
+ next overridded_module_name
89
+ end
90
+ }.compact
91
+
92
+ if dependency_names.count > 0
93
+ pod_dependencies[item.root_name] = dependency_names
94
+ end
95
+ end
96
+
97
+ podfile.sub!("%%%build_settings%%%", podfile_build_settings)
98
+
99
+ podfile.sub!("%%%build_system%%%", Configuration.build_system)
100
+
101
+ podfile.sub!("%%%pods%%%", "\"#{items.map(&:name).join('", "')}\"")
102
+
103
+ podfile.sub!("%%%pods_dependencies%%%", pod_dependencies.to_s)
104
+
105
+ podfile.sub!("%%%targets%%%", items.map(&:entry).join("\n "))
106
+
107
+ return podfile
108
+ end
109
+
110
+ def self.write_restorable(updated_pods, podfile_items, analyzer)
111
+ unless Configuration.restore_enabled && (podfile_items.count + updated_pods.count) > 0
112
+ return
113
+ end
114
+
115
+ puts "Writing Restore Podfile".yellow
116
+
117
+ podfile_items = podfile_items.dup
118
+ podfile_restore_path = PodBuilder::basepath("Podfile.restore")
119
+ podfile_path = PodBuilder::basepath("Podfile")
120
+
121
+ if File.exist?(podfile_restore_path)
122
+ restore_podfile_items = podfile_items_at(podfile_restore_path, include_prebuilt = true)
123
+
124
+ podfile_items.map! { |podfile_item|
125
+ if updated_pod = updated_pods.detect { |x| x.name == podfile_item.name } then
126
+ updated_pod
127
+ elsif updated_pods.any? { |x| podfile_item.root_name == x.root_name } == false && # podfile_item shouldn't be among those being updated (including root specification)
128
+ restored_pod = restore_podfile_items.detect { |x| x.name == podfile_item.name }
129
+ restored_pod
130
+ else
131
+ podfile_item
132
+ end
133
+ }
134
+ end
135
+
136
+ result_targets = analyzer.instance_variable_get("@result").targets.map(&:name)
137
+ podfile_content = ["# Autogenerated by PodBuilder (https://github.com/Subito-it/PodBuilder)", "# Please don't modify this file", "\n"]
138
+ podfile_content += analyzer.podfile.sources.map { |x| "source '#{x}'" }
139
+ podfile_content += ["", "use_frameworks!", ""]
140
+
141
+ # multiple platforms not (yet) supported
142
+ # https://github.com/CocoaPods/Rome/issues/37
143
+ platform = analyzer.instance_variable_get("@result").targets.first.platform
144
+ podfile_content += ["platform :#{platform.name}, '#{platform.deployment_target.version}'", ""]
145
+
146
+ analyzer.instance_variable_get("@result").specs_by_target.each do |target, specifications|
147
+ target_name = target.name.to_s
148
+
149
+ unless result_targets.select { |x| x.end_with?(target_name) }.count > 0
150
+ next
151
+ end
152
+
153
+ podfile_content.push("target '#{target_name}' do")
154
+
155
+ if project_path = target.user_project_path
156
+ podfile_content.push("\tproject '#{project_path}'")
157
+ end
158
+
159
+ specifications.each do |spec|
160
+ item = podfile_items.detect { |x| x.name == spec.name }
161
+ if podfile_items.map(&:name).include?(spec.name)
162
+ podfile_content.push("\t#{item.entry}")
163
+ end
164
+ end
165
+
166
+ podfile_content.push("end\n")
167
+ end
168
+
169
+ File.write(podfile_restore_path, podfile_content.join("\n"))
170
+ end
171
+
172
+ def self.write_prebuilt(all_buildable_items, analyzer)
173
+ if Configuration.react_native_project
174
+ return write_prebuilt_react_native(all_buildable_items, analyzer)
175
+ end
176
+
177
+ puts "Updating Application Podfile".yellow
178
+
179
+ explicit_deps = analyzer.explicit_pods()
180
+ explicit_deps.map! { |t| all_buildable_items.detect { |x| x.name == t.name } }
181
+ explicit_deps.uniq!
182
+ podbuilder_podfile_path = PodBuilder::basepath("Podfile")
183
+ rel_path = Pathname.new(podbuilder_podfile_path).relative_path_from(Pathname.new(PodBuilder::project_path)).to_s
184
+
185
+ podfile_content = File.read(podbuilder_podfile_path)
186
+
187
+ exclude_lines = Podfile::PODBUILDER_LOCK_ACTION.map { |x| strip_line(x) }
188
+
189
+ prebuilt_lines = ["# Autogenerated by PodBuilder (https://github.com/Subito-it/PodBuilder)\n", "# Any change to this file should be done on #{rel_path}\n", "\n"]
190
+ podfile_content.each_line do |line|
191
+ stripped_line = strip_line(line)
192
+ if exclude_lines.include?(stripped_line)
193
+ next
194
+ end
195
+
196
+ if pod_name = pod_definition_in(line, true)
197
+ if podfile_item = all_buildable_items.detect { |x| x.name == pod_name }
198
+ marker = podfile_item.prebuilt_marker()
199
+
200
+ non_explicit_dependencies = podfile_item.recursive_dependencies(all_buildable_items) - explicit_deps
201
+ non_explicit_dependencies_root_names = non_explicit_dependencies.map(&:root_name).uniq.filter { |t| t != podfile_item.root_name }
202
+ non_explicit_dependencies = non_explicit_dependencies_root_names.map { |x|
203
+ if item = all_buildable_items.detect { |t| x == t.name }
204
+ item
205
+ else
206
+ item = all_buildable_items.detect { |t| x == t.root_name }
207
+ end
208
+ }.compact
209
+
210
+ non_explicit_dependencies.each do |dep|
211
+ dep_item = all_buildable_items.detect { |x| x.name == dep.name }
212
+
213
+ if File.exist?(dep_item.prebuilt_podspec_path) && !dep_item.is_prebuilt
214
+ pod_name = dep_item.prebuilt_entry(false, false)
215
+ prebuilt_lines.push("#{line.detect_indentation}#{pod_name}#{marker}\n")
216
+ end
217
+
218
+ explicit_deps.push(dep)
219
+ end
220
+
221
+ if File.exist?(podfile_item.prebuilt_podspec_path) && !podfile_item.is_prebuilt
222
+ prebuilt_lines.push("#{line.detect_indentation}#{podfile_item.prebuilt_entry}\n")
223
+ next
224
+ end
225
+ end
226
+ end
227
+
228
+ prebuilt_lines.push(line)
229
+ end
230
+
231
+ podfile_content = prebuilt_lines.join
232
+
233
+ podfile_content = Podfile.update_path_entries(podfile_content, Podfile.method(:podfile_path_transform))
234
+ podfile_content = Podfile.update_project_entries(podfile_content, Podfile.method(:podfile_path_transform))
235
+ podfile_content = Podfile.update_require_entries(podfile_content, Podfile.method(:podfile_path_transform))
236
+
237
+ podfile_content = add_pre_install_actions(podfile_content)
238
+
239
+ project_podfile_path = PodBuilder::project_path("Podfile")
240
+ File.write(project_podfile_path, podfile_content)
241
+ end
242
+
243
+ def self.write_prebuilt_react_native(all_buildable_items, analyzer)
244
+ puts "Updating Application Podfile".yellow
245
+
246
+ podbuilder_podfile_path = PodBuilder::basepath("Podfile")
247
+ rel_path = Pathname.new(podbuilder_podfile_path).relative_path_from(Pathname.new(PodBuilder::project_path)).to_s
248
+
249
+ podfile_content = ["# Autogenerated by PodBuilder (https://github.com/Subito-it/PodBuilder)\n", "# Any change to this file should be done on #{rel_path}\n", "\n"].join
250
+ podfile_content += analyzer.podfile.pb_to_s(all_buildable_items)
251
+
252
+ podfile_content = Podfile.update_path_entries(podfile_content, PodfileCP.method(:podfile_path_transform))
253
+ podfile_content = Podfile.update_project_entries(podfile_content, Podfile.method(:podfile_path_transform))
254
+ podfile_content = Podfile.update_require_entries(podfile_content, Podfile.method(:podfile_path_transform))
255
+
256
+ podfile_content = add_pre_install_actions(podfile_content)
257
+
258
+ project_podfile_path = PodBuilder::project_path("Podfile")
259
+ File.write(project_podfile_path, podfile_content)
260
+ end
261
+
262
+ def self.install
263
+ puts "Running pod install".yellow
264
+
265
+ Dir.chdir(PodBuilder::project_path) do
266
+ bundler_prefix = Configuration.use_bundler ? "bundle exec " : ""
267
+ system("#{bundler_prefix}pod install;")
268
+ end
269
+ end
270
+
271
+ def self.strip_line(line)
272
+ stripped_line = line.strip
273
+ return stripped_line.gsub("\"", "'").gsub(" ", "").gsub("\t", "").gsub("\n", "")
274
+ end
275
+
276
+ def self.pod_definition_in(line, include_commented)
277
+ stripped_line = strip_line(line)
278
+ matches = stripped_line.match(/(^pod')(.*?)(')/)
279
+
280
+ if matches&.size == 4 && (include_commented || !stripped_line.start_with?("#"))
281
+ return matches[2]
282
+ else
283
+ return nil
284
+ end
285
+ end
286
+
287
+ def self.restore_podfile_clean(pod_items)
288
+ unless Configuration.restore_enabled
289
+ return
290
+ end
291
+
292
+ # remove pods that are no longer listed in pod_items
293
+ podfile_restore_path = PodBuilder::basepath("Podfile.restore")
294
+ unless File.exist?(podfile_restore_path)
295
+ return
296
+ end
297
+
298
+ restore_content = File.read(podfile_restore_path)
299
+
300
+ cleaned_lines = []
301
+ restore_content.each_line do |line|
302
+ if pod_name = pod_definition_in(line, false)
303
+ if pod_items.map(&:name).include?(pod_name)
304
+ cleaned_lines.push(line)
305
+ end
306
+ else
307
+ cleaned_lines.push(line)
308
+ end
309
+ end
310
+
311
+ File.write(podfile_restore_path, cleaned_lines.join)
312
+ end
313
+
314
+ def self.restore_file_sanity_check
315
+ unless Configuration.restore_enabled
316
+ return nil
317
+ end
318
+
319
+ puts "Checking Podfile.restore".yellow
320
+
321
+ podfile_restore_path = PodBuilder::basepath("Podfile.restore")
322
+ unless File.exist?(podfile_restore_path)
323
+ return
324
+ end
325
+
326
+ error = nil
327
+
328
+ begin
329
+ File.rename(PodBuilder::basepath("Podfile"), PodBuilder::basepath("Podfile.tmp2"))
330
+ File.rename(podfile_restore_path, PodBuilder::basepath("Podfile"))
331
+
332
+ Analyze.installer_at(PodBuilder::basepath, false)
333
+ rescue Exception => e
334
+ error = e.to_s
335
+ ensure
336
+ File.rename(PodBuilder::basepath("Podfile"), podfile_restore_path)
337
+ File.rename(PodBuilder::basepath("Podfile.tmp2"), PodBuilder::basepath("Podfile"))
338
+ end
339
+
340
+ if !error.nil?
341
+ FileUtils.rm(podfile_restore_path)
342
+ end
343
+
344
+ return error
345
+ end
346
+
347
+ def self.sanity_check
348
+ podfile_path = PodBuilder::basepath("Podfile")
349
+ unless File.exist?(podfile_path)
350
+ return
351
+ end
352
+
353
+ File.read(podfile_path).each_line do |line|
354
+ stripped_line = strip_line(line)
355
+ unless !stripped_line.start_with?("#")
356
+ next
357
+ end
358
+
359
+ if stripped_line.match(/(pod')(.*?)(')/) != nil
360
+ starting_def_found = stripped_line.start_with?("def") && (line.match("\s*def\s") != nil)
361
+ raise "\n\nUnsupported single line def/pod. `def` and `pod` shouldn't be on the same line, please modify the following line:\n#{line}".red if starting_def_found
362
+ end
363
+ end
364
+ end
365
+
366
+ def self.resolve_pod_names(names, all_buildable_items)
367
+ resolved_names = []
368
+
369
+ names.each do |name|
370
+ if item = all_buildable_items.detect { |t| t.root_name.downcase == name.downcase }
371
+ resolved_names.push(item.root_name)
372
+ end
373
+ end
374
+
375
+ return resolved_names.uniq
376
+ end
377
+
378
+ def self.resolve_pod_names_from_podfile(names)
379
+ resolved_names = []
380
+
381
+ # resolve potentially wrong pod name case
382
+ podfile_path = PodBuilder::basepath("Podfile")
383
+ content = File.read(podfile_path)
384
+
385
+ current_section = ""
386
+ content.each_line do |line|
387
+ matches = line.gsub("\"", "'").match(/pod '(.*?)'/)
388
+ if matches&.size == 2
389
+ if resolved_name = names.detect { |t| matches[1].split("/").first.downcase == t.downcase }
390
+ resolved_names.push(matches[1].split("/").first)
391
+ end
392
+ end
393
+ end
394
+
395
+ resolved_names.uniq
396
+ end
397
+
398
+ def self.install_using_frameworks(analyzer)
399
+ target_settings = analyzer.podfile.target_definition_list.map(&:uses_frameworks?).uniq
400
+ if target_settings.count == 1
401
+ return target_settings.first
402
+ elsif target_settings.count > 1
403
+ raise "\n\n'use_frameworks!' should be declared only once at Podfile root level (not nested in targets)".red
404
+ else
405
+ raise "\n\nFailed detecting use_frameworks!"
406
+ end
407
+
408
+ return true
409
+ end
410
+
411
+ private
412
+
413
+ def self.podfile_path_transform(path)
414
+ use_absolute_paths = false
415
+ podfile_path = PodBuilder::project_path("Podfile")
416
+ original_basepath = PodBuilder::basepath
417
+
418
+ podfile_base_path = Pathname.new(File.dirname(podfile_path))
419
+
420
+ original_path = Pathname.new(File.join(original_basepath, path))
421
+ replace_path = original_path.relative_path_from(podfile_base_path)
422
+ if use_absolute_paths
423
+ replace_path = replace_path.expand_path(podfile_base_path)
424
+ end
425
+
426
+ return replace_path
427
+ end
428
+
429
+ def self.indentation_from_string(content)
430
+ lines = content.split("\n").select { |x| !x.empty? }
431
+
432
+ if lines.count > 2
433
+ lines[0..-2].each_with_index do |current_line, index|
434
+ next_line = lines[index + 1]
435
+ next_line_first_char = next_line.chars.first
436
+ current_doesnt_begin_with_whitespace = current_line[/\A\S*/] != nil
437
+
438
+ if current_doesnt_begin_with_whitespace && [" ", "\t"].include?(next_line_first_char)
439
+ return next_line[/\A\s*/]
440
+ end
441
+ end
442
+ end
443
+
444
+ return " "
445
+ end
446
+
447
+ def self.project_swift_version(analyzer)
448
+ swift_versions = analyzer.instance_variable_get("@result").targets.map { |x| x.target_definition.swift_version }.compact.uniq
449
+
450
+ raise "\n\nFound different Swift versions in targets. Expecting one, got `#{swift_versions}`".red if swift_versions.count > 1
451
+
452
+ return swift_versions.first || PodBuilder::system_swift_version
453
+ end
454
+
455
+ def self.podfile_items_at(podfile_path, include_prebuilt = false)
456
+ raise "\n\nExpecting basepath folder!".red if !File.exist?(PodBuilder::basepath("Podfile"))
457
+
458
+ if File.basename(podfile_path) != "Podfile"
459
+ File.rename(PodBuilder::basepath("Podfile"), PodBuilder::basepath("Podfile.tmp"))
460
+ FileUtils.cp(podfile_path, PodBuilder::basepath("Podfile"))
461
+ end
462
+
463
+ current_dir = Dir.pwd
464
+ Dir.chdir(File.dirname(podfile_path))
465
+
466
+ buildable_items = []
467
+ begin
468
+ installer, analyzer = Analyze.installer_at(PodBuilder::basepath)
469
+
470
+ podfile_items = Analyze.podfile_items(installer, analyzer)
471
+ buildable_items = podfile_items.select { |item| include_prebuilt || !item.is_prebuilt }
472
+ rescue Exception => e
473
+ raise e
474
+ ensure
475
+ Dir.chdir(current_dir)
476
+
477
+ if File.basename(podfile_path) != "Podfile"
478
+ File.rename(PodBuilder::basepath("Podfile.tmp"), PodBuilder::basepath("Podfile"))
479
+ end
480
+ end
481
+
482
+ return buildable_items
483
+ end
484
+
485
+ def self.add_install_block(podfile_content)
486
+ return add(PODBUILDER_LOCK_ACTION, "pre_install", podfile_content)
487
+ end
488
+
489
+ def self.add_pre_install_actions(podfile_content)
490
+ return add(PRE_INSTALL_ACTIONS + [" "], "pre_install", podfile_content)
491
+ end
492
+
493
+ def self.add(entries, marker, podfile_content)
494
+ file_indentation = indentation_from_string(podfile_content)
495
+
496
+ entries = entries.map { |x| "#{file_indentation}#{x}\n"}
497
+
498
+ marker_found = false
499
+ podfile_lines = []
500
+ podfile_content.each_line do |line|
501
+ stripped_line = strip_line(line)
502
+
503
+ podfile_lines.push(line)
504
+ if stripped_line.start_with?("#{marker}do|")
505
+ marker_found = true
506
+ podfile_lines.push(entries)
507
+ end
508
+ end
509
+
510
+ if !marker_found
511
+ if podfile_lines.last.strip.length > 0
512
+ podfile_lines.push("\n")
513
+ end
514
+ podfile_lines.push("\n#{marker} do |installer|\n")
515
+ podfile_lines.push(entries)
516
+ podfile_lines.push("end\n")
517
+ end
518
+
519
+ return podfile_lines.join
520
+ end
521
+
522
+ def self.update_path_entries(podfile_content, path_transform)
523
+ regex = "(\s*pod\s*['|\"])(.*?)(['|\"])(.*?):(path|podspec)(\s*=>\s*['|\"])(.*?)(['|\"])"
524
+
525
+ podfile_lines = []
526
+ podfile_content.each_line do |line|
527
+ stripped_line = strip_line(line)
528
+ matches = line.match(/#{regex}/)
529
+
530
+ if matches&.size == 9 && !stripped_line.start_with?("#")
531
+ pod_name = matches[2]
532
+ path = matches[7]
533
+
534
+ is_absolute = ["~", "/"].include?(path[0])
535
+ unless !PodBuilder::prebuiltpath.end_with?(path) && !is_absolute
536
+ podfile_lines.push(line)
537
+ next
538
+ end
539
+
540
+ replace_path = path_transform.call(path)
541
+
542
+ updated_path_line = line.gsub(/#{regex}/, '\1\2\3\4:\5\6' + replace_path.to_s + '\8\9')
543
+ podfile_lines.push(updated_path_line)
544
+ else
545
+ podfile_lines.push(line)
546
+ end
547
+ end
548
+
549
+ return podfile_lines.join
550
+ end
551
+
552
+ def self.update_project_entries(podfile_content, path_transform)
553
+ regex = "(\s*project\s*['|\"])(.*?)(['|\"])"
554
+
555
+ podfile_lines = []
556
+ podfile_content.each_line do |line|
557
+ stripped_line = strip_line(line)
558
+ matches = line.match(/#{regex}/)
559
+
560
+ if matches&.size == 4 && !stripped_line.start_with?("#")
561
+ path = matches[2]
562
+
563
+ is_absolute = ["~", "/"].include?(path[0])
564
+ unless !is_absolute
565
+ podfile_lines.push(line)
566
+ next
567
+ end
568
+
569
+ replace_path = path_transform.call(path)
570
+
571
+ updated_path_line = line.gsub(/#{regex}/, '\1' + replace_path.to_s + '\3\4')
572
+ podfile_lines.push(updated_path_line)
573
+ else
574
+ podfile_lines.push(line)
575
+ end
576
+ end
577
+
578
+ return podfile_lines.join
579
+ end
580
+
581
+ def self.update_require_entries(podfile_content, path_transform)
582
+ regex = "(\s*require_relative\s*['|\"])(.*?)(['|\"])"
583
+
584
+ podfile_lines = []
585
+ podfile_content.each_line do |line|
586
+ stripped_line = strip_line(line)
587
+ matches = line.match(/#{regex}/)
588
+
589
+ if matches&.size == 4 && !stripped_line.start_with?("#")
590
+ path = matches[2]
591
+
592
+ is_absolute = ["~", "/"].include?(path[0])
593
+ unless !is_absolute
594
+ podfile_lines.push(line)
595
+ next
596
+ end
597
+
598
+ replace_path = path_transform.call(path)
599
+
600
+ updated_path_line = line.gsub(/#{regex}/, '\1' + replace_path.to_s + '\3\4')
601
+ podfile_lines.push(updated_path_line)
602
+ else
603
+ podfile_lines.push(line)
604
+ end
605
+ end
606
+
607
+ return podfile_lines.join
608
+ end
609
+
610
+ def self.prepare_for_react_native_write_pb_configuration(podfile_content)
611
+ base = File.expand_path(File.join(PodBuilder::project_path, ".."))
612
+ bin_js = Dir.glob("#{base}/node_modules/@react-native-community/cli/build/bin.js")
613
+
614
+ raise "\n\nReact native cli bin_js not found! Did you run yarn install?".red unless bin_js.count == 1
615
+ bin_js = bin_js.first
616
+
617
+ config_dest_path = PodBuilder::basepath("rn_config.json")
618
+
619
+ raise "\n\nFailed generating react native configuration file".red unless system("node '#{bin_js}' config > #{config_dest_path}")
620
+
621
+ content = File.read(config_dest_path)
622
+
623
+ content.gsub!(PodBuilder::project_path, "..")
624
+ content.gsub!(File.expand_path(PodBuilder::project_path("..")), "../..")
625
+
626
+ json = JSON.parse(content)
627
+ begin
628
+ json["project"]["ios"]["sourceDir"] = "./"
629
+ json["project"]["ios"]["podfile"] = "./"
630
+ rescue => exception
631
+ raise "\n\nFailed updating react native configuration json".red
632
+ end
633
+
634
+ File.write(config_dest_path, JSON.pretty_generate(json))
635
+
636
+ return "rn_config = JSON.load(File.read(\"rn_config.json\")) # pb added\n\n" + podfile_content
637
+ end
638
+
639
+ def self.prepare_for_react_native_rn_pods_file(podfile_content)
640
+ lines = []
641
+ podfile_content.each_line do |line|
642
+ if line.include?("use_react_native!")
643
+ matches = line.match(/(\s*)/)
644
+ unless matches&.size == 2
645
+ return podfile_content
646
+ end
647
+
648
+ indentation = matches[1]
649
+ lines.push("#{indentation}use_react_native!(:path => rn_config[\"reactNativePath\"]) # pb added\n")
650
+ lines.push("#{indentation}# #{line.strip} # pb removed\n")
651
+ else
652
+ lines.push(line)
653
+ end
654
+ end
655
+
656
+ return lines.join
657
+ end
658
+
659
+ def self.prepare_for_react_native_native_modules_file(podfile_content)
660
+ lines = []
661
+ podfile_content.each_line do |line|
662
+ if line.include?("use_native_modules!")
663
+ matches = line.match(/(\s*)/)
664
+ unless matches&.size == 2
665
+ return podfile_content
666
+ end
667
+
668
+ indentation = matches[1]
669
+ lines.push("#{indentation}use_native_modules!(rn_config) # pb added\n")
670
+ lines.push("#{indentation}# #{line.strip} # pb removed\n")
671
+ else
672
+ lines.push(line)
673
+ end
674
+ end
675
+
676
+ return lines.join
677
+ end
678
+
679
+ def self.prepare_for_react_native(podfile_content)
680
+ original_podfile_content = podfile_content.dup
681
+
682
+ podfile_content = prepare_for_react_native_write_pb_configuration(podfile_content)
683
+ content = prepare_for_react_native_rn_pods_file(podfile_content)
684
+ if content == podfile_content
685
+ return original_podfile_content
686
+ end
687
+ podfile_content = content
688
+ content = prepare_for_react_native_native_modules_file(podfile_content)
689
+ if content == podfile_content
690
+ return original_podfile_content
691
+ end
692
+ podfile_content = content
693
+
694
+ Configuration.build_using_repo_paths = true
695
+ Configuration.react_native_project = true
696
+
697
+ return podfile_content
698
+ end
699
+ end
700
+ end