pod-builder-y 2.3.1

Sign up to get free protection for your applications and to get access to all the features.
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