pod-builder 1.9.3 → 2.0.0.beta.22

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 (95) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +9 -0
  3. data/README.md +50 -13
  4. data/exe/pod_builder +39 -28
  5. data/lib/pod_builder/analyze.rb +32 -7
  6. data/lib/pod_builder/analyzer.rb +16 -0
  7. data/lib/pod_builder/command/build.rb +44 -161
  8. data/lib/pod_builder/command/build_all.rb +2 -2
  9. data/lib/pod_builder/command/clean.rb +34 -55
  10. data/lib/pod_builder/command/clear_lldbinit.rb +7 -3
  11. data/lib/pod_builder/command/deintegrate.rb +29 -7
  12. data/lib/pod_builder/command/generate_lfs.rb +3 -3
  13. data/lib/pod_builder/command/generate_podspec.rb +3 -2
  14. data/lib/pod_builder/command/info.rb +1 -1
  15. data/lib/pod_builder/command/init.rb +37 -14
  16. data/lib/pod_builder/command/install_sources.rb +21 -14
  17. data/lib/pod_builder/command/none.rb +2 -2
  18. data/lib/pod_builder/command/restore_all.rb +4 -4
  19. data/lib/pod_builder/command/switch.rb +137 -95
  20. data/lib/pod_builder/command/sync_podfile.rb +5 -3
  21. data/lib/pod_builder/command/update.rb +5 -6
  22. data/lib/pod_builder/command/update_lldbinit.rb +11 -9
  23. data/lib/pod_builder/configuration.rb +88 -13
  24. data/lib/pod_builder/core.rb +93 -12
  25. data/lib/pod_builder/info.rb +32 -98
  26. data/lib/pod_builder/install.rb +255 -195
  27. data/lib/pod_builder/licenses.rb +4 -4
  28. data/lib/pod_builder/podfile.rb +283 -73
  29. data/lib/pod_builder/podfile/post_actions.rb +9 -15
  30. data/lib/pod_builder/podfile_cp.rb +93 -0
  31. data/lib/pod_builder/podfile_item.rb +181 -82
  32. data/lib/pod_builder/podspec.rb +144 -135
  33. data/lib/pod_builder/rome/post_install.rb +240 -0
  34. data/lib/pod_builder/rome/pre_install.rb +6 -0
  35. data/lib/pod_builder/templates/build_podfile.template +3 -3
  36. data/lib/pod_builder/version.rb +1 -1
  37. data/pod-builder.gemspec +6 -6
  38. metadata +27 -80
  39. data/Example/Frameworks/PodBuilder.json +0 -32
  40. data/Example/PodBuilderExample.xcodeproj/project.pbxproj +0 -416
  41. data/Example/PodBuilderExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
  42. data/Example/PodBuilderExample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
  43. data/Example/PodBuilderExample.xcodeproj/project.xcworkspace/xcuserdata/tomas.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  44. data/Example/PodBuilderExample.xcodeproj/xcuserdata/tomas.xcuserdatad/xcschemes/xcschememanagement.plist +0 -14
  45. data/Example/PodBuilderExample.xcworkspace/contents.xcworkspacedata +0 -10
  46. data/Example/PodBuilderExample/AppDelegate.swift +0 -47
  47. data/Example/PodBuilderExample/Assets.xcassets/AppIcon.appiconset/Contents.json +0 -98
  48. data/Example/PodBuilderExample/Assets.xcassets/Contents.json +0 -6
  49. data/Example/PodBuilderExample/Base.lproj/LaunchScreen.storyboard +0 -25
  50. data/Example/PodBuilderExample/Base.lproj/Main.storyboard +0 -24
  51. data/Example/PodBuilderExample/Info.plist +0 -45
  52. data/Example/PodBuilderExample/ViewController.swift +0 -25
  53. data/Example/Podfile +0 -8
  54. data/Example/Podfile.lock +0 -16
  55. data/Example/Pods/Alamofire/LICENSE +0 -19
  56. data/Example/Pods/Alamofire/README.md +0 -242
  57. data/Example/Pods/Alamofire/Source/AFError.swift +0 -460
  58. data/Example/Pods/Alamofire/Source/Alamofire.swift +0 -465
  59. data/Example/Pods/Alamofire/Source/DispatchQueue+Alamofire.swift +0 -37
  60. data/Example/Pods/Alamofire/Source/MultipartFormData.swift +0 -580
  61. data/Example/Pods/Alamofire/Source/NetworkReachabilityManager.swift +0 -233
  62. data/Example/Pods/Alamofire/Source/Notifications.swift +0 -55
  63. data/Example/Pods/Alamofire/Source/ParameterEncoding.swift +0 -483
  64. data/Example/Pods/Alamofire/Source/Request.swift +0 -654
  65. data/Example/Pods/Alamofire/Source/Response.swift +0 -567
  66. data/Example/Pods/Alamofire/Source/ResponseSerialization.swift +0 -715
  67. data/Example/Pods/Alamofire/Source/Result.swift +0 -300
  68. data/Example/Pods/Alamofire/Source/ServerTrustPolicy.swift +0 -307
  69. data/Example/Pods/Alamofire/Source/SessionDelegate.swift +0 -725
  70. data/Example/Pods/Alamofire/Source/SessionManager.swift +0 -896
  71. data/Example/Pods/Alamofire/Source/TaskDelegate.swift +0 -466
  72. data/Example/Pods/Alamofire/Source/Timeline.swift +0 -136
  73. data/Example/Pods/Alamofire/Source/Validation.swift +0 -315
  74. data/Example/Pods/Manifest.lock +0 -16
  75. data/Example/Pods/Pods.xcodeproj/project.pbxproj +0 -673
  76. data/Example/Pods/Pods.xcodeproj/xcuserdata/tomas.xcuserdatad/xcschemes/Alamofire.xcscheme +0 -60
  77. data/Example/Pods/Pods.xcodeproj/xcuserdata/tomas.xcuserdatad/xcschemes/Pods-PodBuilderExample.xcscheme +0 -60
  78. data/Example/Pods/Pods.xcodeproj/xcuserdata/tomas.xcuserdatad/xcschemes/xcschememanagement.plist +0 -21
  79. data/Example/Pods/Target Support Files/Alamofire/Alamofire-dummy.m +0 -5
  80. data/Example/Pods/Target Support Files/Alamofire/Alamofire-prefix.pch +0 -12
  81. data/Example/Pods/Target Support Files/Alamofire/Alamofire-umbrella.h +0 -16
  82. data/Example/Pods/Target Support Files/Alamofire/Alamofire.modulemap +0 -6
  83. data/Example/Pods/Target Support Files/Alamofire/Alamofire.xcconfig +0 -9
  84. data/Example/Pods/Target Support Files/Alamofire/Info.plist +0 -26
  85. data/Example/Pods/Target Support Files/Pods-PodBuilderExample/Info.plist +0 -26
  86. data/Example/Pods/Target Support Files/Pods-PodBuilderExample/Pods-PodBuilderExample-acknowledgements.markdown +0 -26
  87. data/Example/Pods/Target Support Files/Pods-PodBuilderExample/Pods-PodBuilderExample-acknowledgements.plist +0 -58
  88. data/Example/Pods/Target Support Files/Pods-PodBuilderExample/Pods-PodBuilderExample-dummy.m +0 -5
  89. data/Example/Pods/Target Support Files/Pods-PodBuilderExample/Pods-PodBuilderExample-frameworks.sh +0 -153
  90. data/Example/Pods/Target Support Files/Pods-PodBuilderExample/Pods-PodBuilderExample-resources.sh +0 -118
  91. data/Example/Pods/Target Support Files/Pods-PodBuilderExample/Pods-PodBuilderExample-umbrella.h +0 -16
  92. data/Example/Pods/Target Support Files/Pods-PodBuilderExample/Pods-PodBuilderExample.debug.xcconfig +0 -11
  93. data/Example/Pods/Target Support Files/Pods-PodBuilderExample/Pods-PodBuilderExample.modulemap +0 -6
  94. data/Example/Pods/Target Support Files/Pods-PodBuilderExample/Pods-PodBuilderExample.release.xcconfig +0 -11
  95. data/lib/pod_builder/cocoapods/specification.rb +0 -27
@@ -1,38 +1,8 @@
1
+ # This file contains the logic that generates the .podspec files that are placed
2
+ # along to the prebuild frameworks under PodBuilder/Prebuilt
3
+
1
4
  module PodBuilder
2
5
  class Podspec
3
- class PodspecItem
4
- attr_accessor :name
5
- attr_accessor :module_name
6
- attr_accessor :vendored_frameworks
7
- attr_accessor :vendored_items
8
- attr_accessor :frameworks
9
- attr_accessor :weak_frameworks
10
- attr_accessor :libraries
11
- attr_accessor :resources
12
- attr_accessor :exclude_files
13
- attr_accessor :xcconfig
14
- attr_accessor :dependencies
15
-
16
- def initialize
17
- @name = ""
18
- @module_name = ""
19
- @vendored_frameworks = []
20
- @vendored_items = []
21
- @frameworks = []
22
- @weak_frameworks = []
23
- @libraries = []
24
- @resources = []
25
- @exclude_files = []
26
- @xcconfig = {}
27
- @dependencies = []
28
- end
29
-
30
- def to_s
31
- @name
32
- end
33
- end
34
- private_constant :PodspecItem
35
-
36
6
  def self.generate(all_buildable_items, analyzer)
37
7
  unless all_buildable_items.count > 0
38
8
  return
@@ -40,142 +10,181 @@ module PodBuilder
40
10
 
41
11
  puts "Generating PodBuilder's local podspec".yellow
42
12
 
43
- podspec_items = podspec_items_from(all_buildable_items)
44
-
45
13
  platform = analyzer.instance_variable_get("@result").targets.first.platform
46
- generate_podspec_from(podspec_items, platform)
47
- end
48
-
49
- def self.include?(pod_name)
50
- podspec_path = PodBuilder::basepath("PodBuilder.podspec")
51
- unless File.exist?(podspec_path)
52
- return false
53
- end
54
-
55
- if Configuration.subspecs_to_split.include?(pod_name)
56
- pod_name = pod_name.gsub("/", "_")
57
- else
58
- pod_name = pod_name.split("/").first
59
- end
60
-
61
- podspec_content = File.read(podspec_path)
62
-
63
- # (_.*) will include prebuild podnames like s.subspec 'Podname_Subspec' do |p|
64
- subspec_regex = "s.subspec '#{pod_name}(_.*)?' do |p|"
65
- return (podspec_content.match(/#{subspec_regex}/) != nil)
14
+ generate_podspec_from(all_buildable_items, platform)
66
15
  end
67
16
 
68
17
  private
69
18
 
70
- def self.generate_podspec_from(podspec_items, platform)
71
- podspecs = []
72
- podspec_items.each do |item|
73
- vendored_frameworks = item.vendored_frameworks.map { |x| x.vendored_framework_path }.compact
74
- vendored_frameworks += item.vendored_items.map { |x| File.basename(x) }.select { |x| File.exist?(PodBuilder::basepath(PodfileItem::vendored_name_framework_path(x))) }.map { |x| "Rome/#{x}" }
75
- vendored_frameworks.uniq!
76
- vendored_libraries = Dir.glob(PodBuilder::basepath("Rome/#{item.module_name}/**/*.a")).map { |x| x.to_s.gsub(PodBuilder::basepath, "")[1..-1] }
19
+ def self.generate_spec_keys_for(item, name, all_buildable_items)
20
+ podspec = ""
21
+ valid = false
77
22
 
78
- non_prebuilt_dependencies = item.dependencies.select { |x| x.vendored_framework_path.nil? }
79
-
80
- podspec = " s.subspec '#{item.name.gsub("/", "_")}' do |p|\n"
23
+ slash_count = name.count("/") + 1
24
+ indentation = " " * slash_count
25
+ spec_var = "p#{slash_count}"
81
26
 
27
+ if item.name == name
28
+ if_exists = lambda { |t| File.exist?(PodBuilder::prebuiltpath("#{item.root_name}/#{t}") || "") }
29
+
30
+ vendored_frameworks = item.vendored_frameworks + ["#{item.module_name}.framework"]
31
+ existing_vendored_frameworks = vendored_frameworks.select(&if_exists)
32
+ existing_vendored_frameworks_basename = vendored_frameworks.map { |t| File.basename(t) }.select(&if_exists)
33
+ vendored_frameworks = (existing_vendored_frameworks + existing_vendored_frameworks_basename).uniq
34
+
35
+ vendored_libraries = item.vendored_libraries
36
+ existing_vendored_libraries = vendored_libraries.map { |t| "#{item.module_name}/#{t}" }.select(&if_exists)
37
+ existing_vendored_libraries_basename = vendored_libraries.map { |t| File.basename(t) }.select(&if_exists)
38
+ vendored_libraries = (existing_vendored_libraries + existing_vendored_libraries_basename).uniq
39
+
40
+ # .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)
41
+ vendored_libraries.reject! { |t| t.end_with?(".a") }
42
+
43
+ frameworks = all_buildable_items.select { |t| vendored_frameworks.include?("#{t.module_name}.framework") }.uniq
44
+ static_frameworks = frameworks.select { |x| x.is_static }
45
+
46
+ resources = static_frameworks.map { |x| x.vendored_framework_path.nil? ? nil : "#{x.vendored_framework_path}/*.{nib,bundle,xcasset,strings,png,jpg,tif,tiff,otf,ttf,ttc,plist,json,caf,wav,p12,momd}" }.compact.flatten.uniq
47
+ exclude_files = static_frameworks.map { |x| x.vendored_framework_path.nil? ? nil : "#{x.vendored_framework_path}/Info.plist" }.compact.flatten.uniq
48
+
82
49
  if vendored_frameworks.count > 0
83
- podspec += " p.vendored_frameworks = '#{vendored_frameworks.join("','")}'\n"
84
- end
50
+ podspec += "#{indentation}#{spec_var}.vendored_frameworks = '#{vendored_frameworks.uniq.sort.join("','")}'\n"
51
+ end
85
52
  if vendored_libraries.count > 0
86
- podspec += " p.vendored_libraries = '#{vendored_libraries.join("','")}'\n"
53
+ podspec += "#{indentation}#{spec_var}.vendored_libraries = '#{vendored_libraries.uniq.sort.join("','")}'\n"
87
54
  end
88
55
  if item.frameworks.count > 0
89
- podspec += " p.frameworks = '#{item.frameworks.join("', '")}'\n"
56
+ podspec += "#{indentation}#{spec_var}.frameworks = '#{item.frameworks.uniq.sort.join("', '")}'\n"
90
57
  end
91
58
  if item.libraries.count > 0
92
- podspec += " p.libraries = '#{item.libraries.join("', '")}'\n"
59
+ podspec += "#{indentation}#{spec_var}.libraries = '#{item.libraries.uniq.sort.join("', '")}'\n"
93
60
  end
94
- if item.resources.count > 0
95
- podspec += " p.resources = '#{item.resources.join("', '")}'\n"
61
+ if resources.count > 0
62
+ podspec += "#{indentation}#{spec_var}.resources = '#{resources.uniq.sort.join("', '")}'\n"
96
63
  end
97
- if item.resources.count > 0
98
- podspec += " p.exclude_files = '#{item.exclude_files.join("', '")}'\n"
64
+ if exclude_files.count > 0
65
+ podspec += "#{indentation}#{spec_var}.exclude_files = '#{exclude_files.uniq.sort.join("', '")}'\n"
99
66
  end
100
67
  if item.xcconfig.keys.count > 0
101
- podspec += " p.xcconfig = #{item.xcconfig.to_s}\n"
68
+ xcconfig = Hash.new
69
+ item.xcconfig.each do |k, v|
70
+ unless v != "$(inherited)"
71
+ xcconfig[k] = item.xcconfig[k]
72
+ next
73
+ end
74
+ unless k == "OTHER_LDFLAGS"
75
+ next # For the time being limit to OTHER_LDFLAGS key
76
+ end
77
+
78
+ if podspec_values = item.xcconfig[k]
79
+ podspec_values_arr = podspec_values.split(" ")
80
+ podspec_values_arr.push(v)
81
+ v = podspec_values_arr.join(" ")
82
+ end
83
+
84
+ xcconfig[k] = item.xcconfig[k]
85
+ end
86
+
87
+ if xcconfig.keys.count > 0
88
+ podspec += "#{indentation}#{spec_var}.xcconfig = #{xcconfig.to_s}\n"
89
+ end
90
+ end
91
+
92
+ deps = item.dependency_names.sort
93
+ if name == item.root_name
94
+ deps.reject! { |t| t.split("/").first == item.root_name }
102
95
  end
103
- non_prebuilt_dependencies.each do |non_prebuilt_dependency|
104
- podspec += " p.dependency '#{non_prebuilt_dependency.name}'\n"
96
+
97
+ if deps.count > 0
98
+ if podspec.count("\n") > 1
99
+ podspec += "\n"
100
+ end
101
+ deps.each do |dependency|
102
+ podspec += "#{indentation}#{spec_var}.dependency '#{dependency}'\n"
103
+ end
105
104
  end
106
105
 
107
- podspec += " end"
108
-
109
- podspecs.push(podspec)
106
+ valid = valid || vendored_frameworks.count > 0
110
107
  end
111
108
 
112
- cwd = File.dirname(File.expand_path(__FILE__))
113
- podspec_file = File.read("#{cwd}/templates/build_podspec.template")
114
- podspec_file.gsub!("%%%podspecs%%%", podspecs.join("\n\n"))
115
-
116
- podspec_file.sub!("%%%platform_name%%%", platform.name.to_s)
117
- podspec_file.sub!("%%%deployment_version%%%", platform.deployment_target.version)
118
-
119
- File.write(PodBuilder::basepath("PodBuilder.podspec"), podspec_file)
109
+ subspec_names = all_buildable_items.map(&:name).select { |t| t.start_with?("#{name}/") }
110
+ subspec_names_groups = subspec_names.group_by { |t| name + "/" + t.gsub("#{name}/", '').split("/").first }
111
+ subspec_names = subspec_names_groups.keys.uniq.sort
112
+
113
+ subspec_names.each do |subspec|
114
+ subspec_item = all_buildable_items.detect { |t| t.name == subspec } || item
115
+
116
+ if podspec.length > 0
117
+ podspec += "\n"
118
+ end
119
+
120
+ subspec_keys, subspec_valid = generate_spec_keys_for(subspec_item, subspec, all_buildable_items)
121
+ valid = valid || subspec_valid
122
+
123
+ if subspec_keys.length > 0
124
+ podspec += "#{indentation}#{spec_var}.subspec '#{subspec.split("/").last}' do |p#{slash_count + 1}|\n"
125
+ podspec += subspec_keys
126
+ podspec += "#{indentation}end\n"
127
+ end
128
+ end
129
+
130
+ return podspec, valid
120
131
  end
121
132
 
122
- def self.podspec_items_from(buildable_items)
123
- podspec_items = []
133
+ def self.generate_podspec_from(all_buildable_items, platform)
134
+ prebuilt_podspec_path = all_buildable_items.map(&:prebuilt_podspec_path)
135
+ prebuilt_podspec_path.each do |path|
136
+ if File.exist?(path)
137
+ FileUtils.rm(path)
138
+ end
139
+ end
124
140
 
125
- buildable_items.each do |pod|
126
- spec_exists = File.exist?(PodBuilder::basepath(pod.vendored_spec_framework_path))
127
- subspec_exists = File.exist?(PodBuilder::basepath(pod.vendored_subspec_framework_path))
128
-
129
- unless spec_exists || subspec_exists
130
- puts "Skipping `#{pod.name}`, not prebuilt".blue
141
+ all_buildable_items.each do |item|
142
+ if item.is_prebuilt
131
143
  next
132
144
  end
133
-
134
- pod_name = Configuration.subspecs_to_split.include?(pod.name) ? pod.name : pod.root_name
135
- unless podspec_item = podspec_items.detect { |x| x.name == pod_name }
136
- podspec_item = PodspecItem.new
137
- podspec_items.push(podspec_item)
138
- podspec_item.name = pod_name
139
- podspec_item.module_name = pod.module_name
140
- podspec_item.vendored_items = pod.vendored_items
145
+ if item.name != item.root_name
146
+ if all_buildable_items.map(&:name).include?(item.root_name)
147
+ next # will process root spec, skip subspecs
148
+ end
149
+ end
150
+ if File.exist?(item.prebuilt_podspec_path)
151
+ next # skip if podspec was already generated
141
152
  end
142
-
143
- podspec_item.vendored_frameworks += [pod] + pod.dependencies(buildable_items)
144
-
145
- podspec_item.frameworks = podspec_item.vendored_frameworks.map { |x| x.frameworks }.flatten.uniq.sort
146
- podspec_item.weak_frameworks = podspec_item.vendored_frameworks.map { |x| x.weak_frameworks }.flatten.uniq.sort
147
- podspec_item.libraries = podspec_item.vendored_frameworks.map { |x| x.libraries }.flatten.uniq.sort
148
-
149
- static_vendored_frameworks = podspec_item.vendored_frameworks.select { |x| x.is_static }
150
153
 
151
- podspec_item.resources = static_vendored_frameworks.map { |x| x.vendored_framework_path.nil? ? nil : "#{x.vendored_framework_path}/*.{nib,bundle,xcasset,strings,png,jpg,tif,tiff,otf,ttf,ttc,plist,json,caf,wav,p12,momd}" }.compact.flatten.uniq
152
- podspec_item.exclude_files = static_vendored_frameworks.map { |x| x.vendored_framework_path.nil? ? nil : "#{x.vendored_framework_path}/Info.plist" }.compact.flatten.uniq
153
- podspec_item.exclude_files += podspec_item.vendored_frameworks.map { |x| x.vendored_framework_path.nil? ? nil : "#{x.vendored_framework_path}/#{Configuration.framework_plist_filename}" }.compact.flatten.uniq.sort
154
+ podspec = "Pod::Spec.new do |p1|\n"
154
155
 
155
- # Merge xcconfigs
156
- if !pod.xcconfig.empty?
157
- pod.xcconfig.each do |k, v|
158
- unless v != "$(inherited)"
159
- next
160
- end
161
- unless k == "OTHER_LDFLAGS"
162
- next # For the time being limit to OTHER_LDFLAGS key
163
- end
156
+ podspec += " p1.name = '#{item.root_name}'\n"
157
+ podspec += " p1.version = '#{item.version}'\n"
158
+ podspec += " p1.summary = '#{item.summary.gsub("'", "\\'")}'\n"
159
+ podspec += " p1.homepage = '#{item.homepage}'\n"
160
+ podspec += " p1.author = 'PodBuilder'\n"
161
+ podspec += " p1.source = { 'git' => '#{item.source['git']}'}\n"
162
+ podspec += " p1.license = { :type => '#{item.license}' }\n"
164
163
 
165
- if podspec_values = podspec_item.xcconfig[k]
166
- podspec_values_arr = podspec_values.split(" ")
167
- podspec_values_arr.push(v)
168
- v = podspec_values_arr.join(" ")
169
- end
170
-
171
- podspec_item.xcconfig[k] = v
172
- end
164
+ podspec += "\n"
165
+ podspec += " p1.#{platform.safe_string_name.downcase}.deployment_target = '#{platform.deployment_target.version}'\n"
166
+ podspec += "\n"
167
+
168
+ main_keys, valid = generate_spec_keys_for(item, item.root_name, all_buildable_items)
169
+ if !valid
170
+ next
173
171
  end
174
172
 
175
- podspec_item.dependencies = buildable_items.select { |x| pod.dependency_names.include?(x.name) }
173
+ podspec += main_keys
174
+ podspec += "end"
175
+
176
+ spec_path = item.prebuilt_podspec_path
177
+ if File.directory?(File.dirname(spec_path))
178
+ File.write(spec_path, podspec)
179
+ else
180
+ message = "Prebuilt podspec destination not found for #{File.basename(spec_path)}".red
181
+ if ENV['DEBUGGING']
182
+ puts message
183
+ else
184
+ raise message
185
+ end
186
+ end
176
187
  end
177
-
178
- return podspec_items
179
188
  end
180
189
  end
181
190
  end
@@ -0,0 +1,240 @@
1
+ # TODO: Add support when building without use_frameworks!
2
+
3
+ require 'fourflusher'
4
+ require 'colored'
5
+
6
+ module PodBuilder
7
+ def self.build_for_iosish_platform(sandbox, build_dir, target, device, simulator, configuration, deterministic_build, build_for_apple_silicon)
8
+ raise "\n\nApple silicon hardware still unsupported since it requires to migrate to xcframeworks".red if build_for_apple_silicon
9
+
10
+ dsym_device_folder = File.join(build_dir, "dSYM", device)
11
+ dsym_simulator_folder = File.join(build_dir, "dSYM", simulator)
12
+ FileUtils.mkdir_p(dsym_device_folder)
13
+ FileUtils.mkdir_p(dsym_simulator_folder)
14
+
15
+ deployment_target = target.platform_deployment_target
16
+ target_label = target.cocoapods_target_label
17
+
18
+ xcodebuild(sandbox, target_label, device, deployment_target, configuration, deterministic_build, [])
19
+ excluded_archs = build_for_apple_silicon ? [] : ["arm64"]
20
+ xcodebuild(sandbox, target_label, simulator, deployment_target, configuration, deterministic_build, excluded_archs)
21
+
22
+ spec_names = target.specs.map { |spec| [spec.root.name, spec.root.module_name] }.uniq
23
+ spec_names.each do |root_name, module_name|
24
+ device_base = "#{build_dir}/#{configuration}-#{device}/#{root_name}"
25
+ device_lib = "#{device_base}/#{module_name}.framework/#{module_name}"
26
+ device_dsym = "#{device_base}/#{module_name}.framework.dSYM"
27
+ device_framework_lib = File.dirname(device_lib)
28
+ device_swift_header_path = "#{device_framework_lib}/Headers/#{module_name}-Swift.h"
29
+
30
+ simulator_base = "#{build_dir}/#{configuration}-#{simulator}/#{root_name}"
31
+ simulator_lib = "#{simulator_base}/#{module_name}.framework/#{module_name}"
32
+ simulator_dsym = "#{simulator_base}/#{module_name}.framework.dSYM"
33
+ simulator_framework_lib = File.dirname(simulator_lib)
34
+ simulator_swift_header_path = "#{simulator_framework_lib}/Headers/#{module_name}-Swift.h"
35
+
36
+ next unless File.file?(device_lib) && File.file?(simulator_lib)
37
+
38
+ # Starting with Xcode 12b3 the simulator binary contains an arm64 slice as well which conflict with the one in the device_lib
39
+ # when creating the fat library. A naive workaround is to remove the arm64 from the simulator_lib however this is wrong because
40
+ # we might actually need to have 2 separated arm64 slices, one for simulator and one for device each built with different
41
+ # compile time directives (e.g #if targetEnvironment(simulator))
42
+ #
43
+ # For the time being we remove the arm64 slice bacause otherwise the `xcrun lipo -create -output ...` would fail.
44
+ if `xcrun lipo -info #{simulator_lib}`.include?("arm64")
45
+ `xcrun lipo -remove arm64 #{simulator_lib} -o #{simulator_lib}`
46
+ end
47
+
48
+ raise "Lipo failed on #{device_lib}" unless system("xcrun lipo -create -output #{device_lib} #{device_lib} #{simulator_lib}")
49
+
50
+ # Merge swift headers as per Xcode 10.2 release notes
51
+ if File.exist?(device_swift_header_path) && File.exist?(simulator_swift_header_path)
52
+ device_content = File.read(device_swift_header_path)
53
+ simulator_content = File.read(simulator_swift_header_path)
54
+ merged_content = %{
55
+ #if TARGET_OS_SIMULATOR
56
+ #{simulator_content}
57
+ #else
58
+ #{device_content}
59
+ #endif
60
+ }
61
+ File.write(device_swift_header_path, merged_content)
62
+ end
63
+
64
+ # Merge device framework into simulator framework (so that e.g swift Module folder is merged)
65
+ # letting device framework files overwrite simulator ones
66
+ FileUtils.cp_r(File.join(device_framework_lib, "."), simulator_framework_lib)
67
+ source_lib = File.dirname(simulator_framework_lib)
68
+
69
+ FileUtils.cp_r(source_lib, build_dir)
70
+
71
+ FileUtils.cp_r(device_dsym, dsym_device_folder) if File.exist?(device_dsym)
72
+ FileUtils.cp_r(simulator_dsym, dsym_simulator_folder) if File.exist?(simulator_dsym)
73
+
74
+ # Remove frameworks leaving dSYMs
75
+ FileUtils.rm_rf(device_framework_lib)
76
+ FileUtils.rm_rf(simulator_framework_lib)
77
+ end
78
+ end
79
+
80
+ def self.xcodebuild(sandbox, target, sdk='macosx', deployment_target=nil, configuration, deterministic_build, exclude_archs)
81
+ args = %W(-project #{sandbox.project_path.realdirpath} -scheme #{target} -configuration #{configuration} -sdk #{sdk})
82
+ supported_platforms = { 'iphonesimulator' => 'iOS', 'appletvsimulator' => 'tvOS', 'watchsimulator' => 'watchOS' }
83
+ if platform = supported_platforms[sdk]
84
+ args += Fourflusher::SimControl.new.destination(:oldest, platform, deployment_target) unless platform.nil?
85
+ end
86
+
87
+ xcodebuild_version = `xcodebuild -version | head -n1 | awk '{print $2}'`.strip().to_f
88
+ if exclude_archs.count > 0 && xcodebuild_version >= 12.0
89
+ args += ["EXCLUDED_ARCHS=#{exclude_archs.join(" ")}"]
90
+ end
91
+
92
+ environmental_variables = {}
93
+ if deterministic_build
94
+ environmental_variables["ZERO_AR_DATE"] = "1"
95
+ end
96
+
97
+ execute_command 'xcodebuild', args, true, environmental_variables
98
+ end
99
+
100
+ # Copy paste implementation from CocoaPods internals to be able to call poopen3 passing environmental variables
101
+ def self.execute_command(executable, command, raise_on_failure = true, environmental_variables = {})
102
+ bin = Pod::Executable.which!(executable)
103
+
104
+ command = command.map(&:to_s)
105
+ full_command = "#{bin} #{command.join(' ')}"
106
+
107
+ stdout = Pod::Executable::Indenter.new
108
+ stderr = Pod::Executable::Indenter.new
109
+
110
+ status = popen3(bin, command, stdout, stderr, environmental_variables)
111
+ stdout = stdout.join
112
+ stderr = stderr.join
113
+ output = stdout + stderr
114
+ unless status.success?
115
+ if raise_on_failure
116
+ raise "#{full_command}\n\n#{output}"
117
+ else
118
+ UI.message("[!] Failed: #{full_command}".red)
119
+ end
120
+ end
121
+
122
+ output
123
+ end
124
+
125
+ def self.popen3(bin, command, stdout, stderr, environmental_variables)
126
+ require 'open3'
127
+ Open3.popen3(environmental_variables, bin, *command) do |i, o, e, t|
128
+ Pod::Executable::reader(o, stdout)
129
+ Pod::Executable::reader(e, stderr)
130
+ i.close
131
+
132
+ status = t.value
133
+
134
+ o.flush
135
+ e.flush
136
+ sleep(0.01)
137
+
138
+ status
139
+ end
140
+ end
141
+
142
+ def self.enable_debug_information(project_path, configuration)
143
+ project = Xcodeproj::Project.open(project_path)
144
+ project.targets.each do |target|
145
+ config = target.build_configurations.find { |config| config.name.eql? configuration }
146
+ config.build_settings['DEBUG_INFORMATION_FORMAT'] = 'dwarf-with-dsym'
147
+ config.build_settings['ONLY_ACTIVE_ARCH'] = 'NO'
148
+ end
149
+ project.save
150
+ end
151
+
152
+
153
+ end
154
+
155
+ Pod::HooksManager.register('podbuilder-rome', :post_install) do |installer_context, user_options|
156
+ enable_dsym = user_options.fetch('dsym', true)
157
+ configuration = user_options.fetch('configuration', 'Debug')
158
+ if user_options["pre_compile"]
159
+ user_options["pre_compile"].call(installer_context)
160
+ end
161
+
162
+ sandbox_root = Pathname(installer_context.sandbox_root)
163
+ sandbox = Pod::Sandbox.new(sandbox_root)
164
+
165
+ PodBuilder::enable_debug_information(sandbox.project_path, configuration)
166
+
167
+ build_dir = sandbox_root.parent + 'build'
168
+ base_destination = sandbox_root.parent + 'Prebuilt'
169
+
170
+ build_dir.rmtree if build_dir.directory?
171
+ targets = installer_context.umbrella_targets.select { |t| t.specs.any? }
172
+ targets.each do |target|
173
+ case target.platform_name
174
+ when :ios then PodBuilder::build_for_iosish_platform(sandbox, build_dir, target, 'iphoneos', 'iphonesimulator', configuration, PodBuilder::Configuration.deterministic_build, PodBuilder::Configuration.build_for_apple_silicon)
175
+ when :osx then PodBuilder::xcodebuild(sandbox, target.cocoapods_target_label, configuration, PodBuilder::Configuration.deterministic_build, PodBuilder::Configuration.build_for_apple_silicon)
176
+ when :tvos then PodBuilder::build_for_iosish_platform(sandbox, build_dir, target, 'appletvos', 'appletvsimulator', configuration, PodBuilder::Configuration.deterministic_build, PodBuilder::Configuration.build_for_apple_silicon)
177
+ when :watchos then PodBuilder::build_for_iosish_platform(sandbox, build_dir, target, 'watchos', 'watchsimulator', configuration, PodBuilder::Configuration.deterministic_build, PodBuilder::Configuration.build_for_apple_silicon)
178
+ else raise "\n\nUnknown platform '#{target.platform_name}'".red end
179
+ end
180
+
181
+ raise Pod::Informative, 'The build directory was not found in the expected location.' unless build_dir.directory?
182
+
183
+ built_count = installer_context.umbrella_targets.map { |t| t.specs.map(&:name) }.flatten.map { |t| t.split("/").first }.uniq.count
184
+ Pod::UI.puts "Built #{built_count} #{'items'.pluralize(built_count)}, copying..."
185
+
186
+ base_destination.rmtree if base_destination.directory?
187
+
188
+ installer_context.umbrella_targets.each do |umbrella|
189
+ umbrella.specs.each do |spec|
190
+ root_name = spec.name.split("/").first
191
+ # Make sure the device target overwrites anything in the simulator build, otherwise iTunesConnect
192
+ # can get upset about Info.plist containing references to the simulator SDK
193
+ frameworks = Pathname.glob("build/#{root_name}/*.framework").reject { |f| f.to_s =~ /Pods[^.]+\.framework/ }
194
+
195
+ consumer = spec.consumer(umbrella.platform_name)
196
+ file_accessor = Pod::Sandbox::FileAccessor.new(sandbox.pod_dir(spec.root.name), consumer)
197
+ frameworks += file_accessor.vendored_libraries
198
+ frameworks += file_accessor.vendored_frameworks
199
+ resources = file_accessor.resources
200
+
201
+ destination = File.join(base_destination, root_name)
202
+ FileUtils.mkdir_p(destination)
203
+
204
+ files = frameworks + resources
205
+ files.each do |file|
206
+ FileUtils.cp_r(file, destination)
207
+ end
208
+ end
209
+ end
210
+
211
+ # Depending on the resource it may happen that it is present twice, both in the .framework and in the parent folder
212
+ Dir.glob("#{base_destination}/*") do |path|
213
+ unless File.directory?(path)
214
+ return
215
+ end
216
+
217
+ files = Dir.glob("#{path}/*")
218
+ framework_files = Dir.glob("#{path}/*.framework/**/*").map { |t| File.basename(t) }
219
+
220
+ files.each do |file|
221
+ filename = File.basename(file.gsub(/\.xib$/, ".nib"))
222
+ if framework_files.include?(filename)
223
+ FileUtils.rm_rf(file)
224
+ end
225
+ end
226
+ end
227
+
228
+ if enable_dsym
229
+ FileUtils.mv("#{build_dir}/dSYM", sandbox_root.parent)
230
+ else
231
+ raise "Not implemented"
232
+ end
233
+
234
+ build_dir.rmtree if build_dir.directory?
235
+
236
+ if user_options["post_compile"]
237
+ user_options["post_compile"].call(installer_context)
238
+ end
239
+ end
240
+