cocoapods-packager-next 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +4 -0
  4. data/.rubocop-cocoapods.yml +71 -0
  5. data/.rubocop.yml +38 -0
  6. data/.travis.yml +17 -0
  7. data/Gemfile +12 -0
  8. data/Gemfile.lock +129 -0
  9. data/LICENSE +22 -0
  10. data/README.md +39 -0
  11. data/Rakefile +29 -0
  12. data/cocoapods-packager-next.gemspec +22 -0
  13. data/lib/cocoapods-packager/builder.rb +334 -0
  14. data/lib/cocoapods-packager/framework.rb +66 -0
  15. data/lib/cocoapods-packager/mangle.rb +32 -0
  16. data/lib/cocoapods-packager/pod_utils.rb +250 -0
  17. data/lib/cocoapods-packager/spec_builder.rb +63 -0
  18. data/lib/cocoapods-packager/symbols.rb +42 -0
  19. data/lib/cocoapods-packager/user_interface/build_failed_report.rb +15 -0
  20. data/lib/cocoapods_packager.rb +5 -0
  21. data/lib/cocoapods_plugin.rb +8 -0
  22. data/lib/pod/command/package.rb +177 -0
  23. data/scripts/lstconst.sh +9 -0
  24. data/scripts/lstsym.sh +8 -0
  25. data/spec/command/error_spec.rb +81 -0
  26. data/spec/command/package_spec.rb +420 -0
  27. data/spec/command/subspecs_spec.rb +30 -0
  28. data/spec/fixtures/Archs.podspec +13 -0
  29. data/spec/fixtures/Builder.podspec +25 -0
  30. data/spec/fixtures/CPDColors.podspec +19 -0
  31. data/spec/fixtures/FH.podspec +18 -0
  32. data/spec/fixtures/KFData.podspec +73 -0
  33. data/spec/fixtures/LibraryConsumerDemo/.gitignore +22 -0
  34. data/spec/fixtures/LibraryConsumerDemo/LibraryConsumer/AppDelegate.h +17 -0
  35. data/spec/fixtures/LibraryConsumerDemo/LibraryConsumer/AppDelegate.m +27 -0
  36. data/spec/fixtures/LibraryConsumerDemo/LibraryConsumer/Info.plist +40 -0
  37. data/spec/fixtures/LibraryConsumerDemo/LibraryConsumer/main.m +16 -0
  38. data/spec/fixtures/LibraryConsumerDemo/LibraryConsumer.xcodeproj/project.pbxproj +311 -0
  39. data/spec/fixtures/LibraryConsumerDemo/LibraryConsumer.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  40. data/spec/fixtures/LibraryConsumerDemo/LibraryConsumer.xcodeproj/xcshareddata/xcschemes/LibraryConsumer.xcscheme +100 -0
  41. data/spec/fixtures/LibraryConsumerDemo/LibraryConsumer.xcworkspace/contents.xcworkspacedata +10 -0
  42. data/spec/fixtures/LibraryConsumerDemo/Podfile +5 -0
  43. data/spec/fixtures/LibraryDemo.podspec +14 -0
  44. data/spec/fixtures/LocalSources/LICENSE +0 -0
  45. data/spec/fixtures/LocalSources/LocalNikeKit.h +4 -0
  46. data/spec/fixtures/LocalSources/LocalNikeKit.m +9 -0
  47. data/spec/fixtures/LocalSources/LocalNikeKit.podspec +19 -0
  48. data/spec/fixtures/NikeKit.podspec +19 -0
  49. data/spec/fixtures/OpenSans.podspec +18 -0
  50. data/spec/fixtures/PackagerTest/.gitignore +21 -0
  51. data/spec/fixtures/PackagerTest/PackagerTest/CPDAppDelegate.h +15 -0
  52. data/spec/fixtures/PackagerTest/PackagerTest/CPDAppDelegate.m +49 -0
  53. data/spec/fixtures/PackagerTest/PackagerTest/Images.xcassets/AppIcon.appiconset/Contents.json +23 -0
  54. data/spec/fixtures/PackagerTest/PackagerTest/Images.xcassets/LaunchImage.launchimage/Contents.json +23 -0
  55. data/spec/fixtures/PackagerTest/PackagerTest/PackagerTest-Info.plist +38 -0
  56. data/spec/fixtures/PackagerTest/PackagerTest/PackagerTest-Prefix.pch +16 -0
  57. data/spec/fixtures/PackagerTest/PackagerTest/en.lproj/InfoPlist.strings +2 -0
  58. data/spec/fixtures/PackagerTest/PackagerTest/main.m +18 -0
  59. data/spec/fixtures/PackagerTest/PackagerTest.xcodeproj/project.pbxproj +507 -0
  60. data/spec/fixtures/PackagerTest/PackagerTest.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  61. data/spec/fixtures/PackagerTest/PackagerTest.xcodeproj/xcshareddata/xcschemes/PackagerTest.xcscheme +110 -0
  62. data/spec/fixtures/PackagerTest/PackagerTest.xcworkspace/contents.xcworkspacedata +1 -0
  63. data/spec/fixtures/PackagerTest/PackagerTestTests/PackagerTestTests-Info.plist +22 -0
  64. data/spec/fixtures/PackagerTest/PackagerTestTests/PackagerTestTests.m +34 -0
  65. data/spec/fixtures/PackagerTest/PackagerTestTests/en.lproj/InfoPlist.strings +2 -0
  66. data/spec/fixtures/PackagerTest/Podfile +10 -0
  67. data/spec/fixtures/PackagerTest/Podfile.lock +36 -0
  68. data/spec/fixtures/Weakly.podspec +13 -0
  69. data/spec/fixtures/a.podspec +19 -0
  70. data/spec/fixtures/foo-bar.podspec +19 -0
  71. data/spec/fixtures/layer-client-messaging-schema.podspec +13 -0
  72. data/spec/integration/project_spec.rb +70 -0
  73. data/spec/spec_helper.rb +79 -0
  74. data/spec/unit/pod/utils_spec.rb +58 -0
  75. data/spec/unit/specification/builder_spec.rb +62 -0
  76. data/spec/unit/specification/spec_builder_spec.rb +61 -0
  77. data/spec/unit/user_interface/build_failed_report_spec.rb +11 -0
  78. metadata +223 -0
@@ -0,0 +1,334 @@
1
+ module Pod
2
+ class Builder
3
+ def initialize(platform, static_installer, source_dir, static_sandbox_root, dynamic_sandbox_root, public_headers_root, spec, embedded, mangle, dynamic, config, bundle_identifier, exclude_deps)
4
+ @platform = platform
5
+ @static_installer = static_installer
6
+ @source_dir = source_dir
7
+ @static_sandbox_root = static_sandbox_root
8
+ @dynamic_sandbox_root = dynamic_sandbox_root
9
+ @public_headers_root = public_headers_root
10
+ @spec = spec
11
+ @embedded = embedded
12
+ @mangle = mangle
13
+ @dynamic = dynamic
14
+ @config = config
15
+ @bundle_identifier = bundle_identifier
16
+ @exclude_deps = exclude_deps
17
+
18
+ @file_accessors = @static_installer.pod_targets.select { |t| t.pod_name == @spec.name }.flat_map(&:file_accessors)
19
+ end
20
+
21
+ def build(package_type)
22
+ case package_type
23
+ when :static_library
24
+ build_static_library
25
+ when :static_framework
26
+ build_static_framework
27
+ when :dynamic_framework
28
+ build_dynamic_framework
29
+ end
30
+ end
31
+
32
+ def build_static_library
33
+ UI.puts("Building static library #{@spec} with configuration #{@config}")
34
+
35
+ defines = compile
36
+ build_sim_libraries(defines)
37
+
38
+ platform_path = Pathname.new(@platform.name.to_s)
39
+ platform_path.mkdir unless platform_path.exist?
40
+
41
+ output = platform_path + "lib#{@spec.name}.a"
42
+
43
+ if @platform.name == :ios
44
+ build_static_library_for_ios(output)
45
+ else
46
+ build_static_library_for_mac(output)
47
+ end
48
+ end
49
+
50
+ def build_static_framework
51
+ UI.puts("Building static framework #{@spec} with configuration #{@config}")
52
+
53
+ defines = compile
54
+ build_sim_libraries(defines)
55
+
56
+ create_framework
57
+ output = @fwk.versions_path + Pathname.new(@spec.name)
58
+
59
+ if @platform.name == :ios
60
+ build_static_library_for_ios(output)
61
+ else
62
+ build_static_library_for_mac(output)
63
+ end
64
+
65
+ copy_headers
66
+ copy_license
67
+ copy_resources
68
+ end
69
+
70
+ def link_embedded_resources
71
+ target_path = @fwk.root_path + Pathname.new('Resources')
72
+ target_path.mkdir unless target_path.exist?
73
+
74
+ Dir.glob(@fwk.resources_path.to_s + '/*').each do |resource|
75
+ resource = Pathname.new(resource).relative_path_from(target_path)
76
+ `ln -sf #{resource} #{target_path}`
77
+ end
78
+ end
79
+
80
+ def build_dynamic_framework
81
+ UI.puts("Building dynamic framework #{@spec} with configuration #{@config}")
82
+
83
+ defines = compile
84
+ build_sim_libraries(defines)
85
+
86
+ if @bundle_identifier
87
+ defines = "#{defines} PRODUCT_BUNDLE_IDENTIFIER='#{@bundle_identifier}'"
88
+ end
89
+
90
+ output = "#{@dynamic_sandbox_root}/build/#{@spec.name}.framework/#{@spec.name}"
91
+
92
+ clean_directory_for_dynamic_build
93
+ if @platform.name == :ios
94
+ build_dynamic_framework_for_ios(defines, output)
95
+ else
96
+ build_dynamic_framework_for_mac(defines, output)
97
+ end
98
+
99
+ copy_resources
100
+ end
101
+
102
+ def build_dynamic_framework_for_ios(defines, output)
103
+ # Specify frameworks to link and search paths
104
+ linker_flags = static_linker_flags_in_sandbox
105
+ defines = "#{defines} OTHER_LDFLAGS='$(inherited) #{linker_flags.join(' ')}'"
106
+
107
+ # Build Target Dynamic Framework for both device and Simulator
108
+ device_defines = "#{defines} LIBRARY_SEARCH_PATHS=\"#{Dir.pwd}/#{@static_sandbox_root}/build\""
109
+ device_options = ios_build_options << ' -sdk iphoneos'
110
+ xcodebuild(device_defines, device_options, 'build', @spec.name.to_s, @dynamic_sandbox_root.to_s)
111
+
112
+ sim_defines = "#{defines} LIBRARY_SEARCH_PATHS=\"#{Dir.pwd}/#{@static_sandbox_root}/build-sim\" ONLY_ACTIVE_ARCH=NO"
113
+ xcodebuild(sim_defines, '-sdk iphonesimulator', 'build-sim', @spec.name.to_s, @dynamic_sandbox_root.to_s)
114
+
115
+ # Combine architectures
116
+ `lipo #{@dynamic_sandbox_root}/build/#{@spec.name}.framework/#{@spec.name} #{@dynamic_sandbox_root}/build-sim/#{@spec.name}.framework/#{@spec.name} -create -output #{output}`
117
+
118
+ FileUtils.mkdir(@platform.name.to_s)
119
+ `mv #{@dynamic_sandbox_root}/build/#{@spec.name}.framework #{@platform.name}`
120
+ `mv #{@dynamic_sandbox_root}/build/#{@spec.name}.framework.dSYM #{@platform.name}`
121
+ end
122
+
123
+ def build_dynamic_framework_for_mac(defines, _output)
124
+ # Specify frameworks to link and search paths
125
+ linker_flags = static_linker_flags_in_sandbox
126
+ defines = "#{defines} OTHER_LDFLAGS=\"#{linker_flags.join(' ')}\""
127
+
128
+ # Build Target Dynamic Framework for osx
129
+ defines = "#{defines} LIBRARY_SEARCH_PATHS=\"#{Dir.pwd}/#{@static_sandbox_root}/build\""
130
+ xcodebuild(defines, nil, 'build', @spec.name.to_s, @dynamic_sandbox_root.to_s)
131
+
132
+ FileUtils.mkdir(@platform.name.to_s)
133
+ `mv #{@dynamic_sandbox_root}/build/#{@spec.name}.framework #{@platform.name}`
134
+ `mv #{@dynamic_sandbox_root}/build/#{@spec.name}.framework.dSYM #{@platform.name}`
135
+ end
136
+
137
+ def build_sim_libraries(defines)
138
+ if @platform.name == :ios
139
+ xcodebuild(defines, '-sdk iphonesimulator', 'build-sim')
140
+ end
141
+ end
142
+
143
+ def build_static_library_for_ios(output)
144
+ static_libs = static_libs_in_sandbox('build') + static_libs_in_sandbox('build-sim') + vendored_libraries
145
+ libs = ios_architectures.map do |arch|
146
+ library = "#{@static_sandbox_root}/build/package-#{arch}.a"
147
+ `libtool -arch_only #{arch} -static -o #{library} #{static_libs.join(' ')}`
148
+ library
149
+ end
150
+
151
+ `lipo -create -output #{output} #{libs.join(' ')}`
152
+ end
153
+
154
+ def build_static_library_for_mac(output)
155
+ static_libs = static_libs_in_sandbox + vendored_libraries
156
+ `libtool -static -o #{output} #{static_libs.join(' ')}`
157
+ end
158
+
159
+ def build_with_mangling(options)
160
+ UI.puts 'Mangling symbols'
161
+ defines = Symbols.mangle_for_pod_dependencies(@spec.name, @static_sandbox_root)
162
+ defines << ' ' << @spec.consumer(@platform).compiler_flags.join(' ')
163
+
164
+ UI.puts 'Building mangled framework'
165
+ xcodebuild(defines, options)
166
+ defines
167
+ end
168
+
169
+ def clean_directory_for_dynamic_build
170
+ # Remove static headers to avoid duplicate declaration conflicts
171
+ FileUtils.rm_rf("#{@static_sandbox_root}/Headers/Public/#{@spec.name}")
172
+ FileUtils.rm_rf("#{@static_sandbox_root}/Headers/Private/#{@spec.name}")
173
+
174
+ # Equivalent to removing derrived data
175
+ FileUtils.rm_rf('Pods/build')
176
+ end
177
+
178
+ def compile
179
+ defines = "GCC_PREPROCESSOR_DEFINITIONS='$(inherited) PodsDummy_Pods_#{@spec.name}=PodsDummy_PodPackage_#{@spec.name}'"
180
+ defines << ' ' << @spec.consumer(@platform).compiler_flags.join(' ')
181
+
182
+ if @platform.name == :ios
183
+ options = ios_build_options
184
+ end
185
+
186
+ xcodebuild(defines, options)
187
+
188
+ if @mangle
189
+ return build_with_mangling(options)
190
+ end
191
+
192
+ defines
193
+ end
194
+
195
+ def copy_headers
196
+ headers_source_root = "#{@public_headers_root}/#{@spec.name}"
197
+
198
+ Dir.glob("#{headers_source_root}/**/*.h").
199
+ each { |h| `ditto #{h} #{@fwk.headers_path}/#{h.sub(headers_source_root, '')}` }
200
+
201
+ # If custom 'module_map' is specified add it to the framework distribution
202
+ # otherwise check if a header exists that is equal to 'spec.name', if so
203
+ # create a default 'module_map' one using it.
204
+ if !@spec.module_map.nil?
205
+ module_map_file = @file_accessors.flat_map(&:module_map).first
206
+ module_map = File.read(module_map_file) if Pathname(module_map_file).exist?
207
+ elsif File.exist?("#{@public_headers_root}/#{@spec.name}/#{@spec.name}.h")
208
+ module_map = <<MAP
209
+ framework module #{@spec.name} {
210
+ umbrella header "#{@spec.name}.h"
211
+
212
+ export *
213
+ module * { export * }
214
+ }
215
+ MAP
216
+ end
217
+
218
+ unless module_map.nil?
219
+ @fwk.module_map_path.mkpath unless @fwk.module_map_path.exist?
220
+ File.write("#{@fwk.module_map_path}/module.modulemap", module_map)
221
+ end
222
+ end
223
+
224
+ def copy_license
225
+ license_file = @spec.license[:file] || 'LICENSE'
226
+ license_file = Pathname.new("#{@static_sandbox_root}/#{@spec.name}/#{license_file}")
227
+ FileUtils.cp(license_file, '.') if license_file.exist?
228
+ end
229
+
230
+ def copy_resources
231
+ bundles = Dir.glob("#{@static_sandbox_root}/build/*.bundle")
232
+ if @dynamic
233
+ resources_path = "ios/#{@spec.name}.framework"
234
+ `cp -rp #{@static_sandbox_root}/build/*.bundle #{resources_path} 2>&1`
235
+ else
236
+ `cp -rp #{@static_sandbox_root}/build/*.bundle #{@fwk.resources_path} 2>&1`
237
+ resources = expand_paths(@spec.consumer(@platform).resources)
238
+ if resources.count == 0 && bundles.count == 0
239
+ @fwk.delete_resources
240
+ return
241
+ end
242
+ if resources.count > 0
243
+ `cp -rp #{resources.join(' ')} #{@fwk.resources_path}`
244
+ end
245
+ end
246
+ end
247
+
248
+ def create_framework
249
+ @fwk = Framework::Tree.new(@spec.name, @platform.name.to_s, @embedded)
250
+ @fwk.make
251
+ end
252
+
253
+ def dependency_count
254
+ count = @spec.dependencies.count
255
+
256
+ @spec.subspecs.each do |subspec|
257
+ count += subspec.dependencies.count
258
+ end
259
+
260
+ count
261
+ end
262
+
263
+ def expand_paths(path_specs)
264
+ path_specs.map do |path_spec|
265
+ Dir.glob(File.join(@source_dir, path_spec))
266
+ end
267
+ end
268
+
269
+ def static_libs_in_sandbox(build_dir = 'build')
270
+ if @exclude_deps
271
+ UI.puts 'Excluding dependencies'
272
+ Dir.glob("#{@static_sandbox_root}/#{build_dir}/lib#{@spec.name}.a")
273
+ else
274
+ Dir.glob("#{@static_sandbox_root}/#{build_dir}/lib*.a")
275
+ end
276
+ end
277
+
278
+ def vendored_libraries
279
+ if @vendored_libraries
280
+ @vendored_libraries
281
+ end
282
+ file_accessors = if @exclude_deps
283
+ @file_accessors
284
+ else
285
+ @static_installer.pod_targets.flat_map(&:file_accessors)
286
+ end
287
+ libs = file_accessors.flat_map(&:vendored_static_frameworks).map { |f| f + f.basename('.*') } || []
288
+ libs += file_accessors.flat_map(&:vendored_static_libraries)
289
+ @vendored_libraries = libs.compact.map(&:to_s)
290
+ @vendored_libraries
291
+ end
292
+
293
+ def static_linker_flags_in_sandbox
294
+ linker_flags = static_libs_in_sandbox.map do |lib|
295
+ lib.slice!('lib')
296
+ lib_flag = lib.chomp('.a').split('/').last
297
+ "-l#{lib_flag}"
298
+ end
299
+ linker_flags.reject { |e| e == "-l#{@spec.name}" || e == '-lPods-packager' }
300
+ end
301
+
302
+ def ios_build_options
303
+ "ARCHS=\'$(ARCHS_STANDARD)\' OTHER_CFLAGS=\'-fembed-bitcode -Qunused-arguments\'"
304
+ end
305
+
306
+ def ios_architectures
307
+ archs = %w(x86_64 i386 arm64 armv7 armv7s)
308
+ vendored_libraries.each do |library|
309
+ archs = `lipo -info #{library}`.split & archs
310
+ end
311
+ archs
312
+ end
313
+
314
+ def xcodebuild(defines = '', args = '', build_dir = 'build', target = 'Pods-packager', project_root = @static_sandbox_root, config = @config)
315
+ if defined?(Pod::DONT_CODESIGN)
316
+ args = "#{args} CODE_SIGN_IDENTITY=\"\" CODE_SIGNING_REQUIRED=NO"
317
+ end
318
+
319
+ command = "xcodebuild #{defines} #{args} CONFIGURATION_BUILD_DIR=#{build_dir} clean build -configuration #{config} -target #{target} -project #{project_root}/Pods.xcodeproj 2>&1"
320
+ output = `#{command}`.lines.to_a
321
+
322
+ if $?.exitstatus != 0
323
+ puts UI::BuildFailedReport.report(command, output)
324
+
325
+ # Note: We use `Process.exit` here because it fires a `SystemExit`
326
+ # exception, which gives the caller a chance to clean up before the
327
+ # process terminates.
328
+ #
329
+ # See http://ruby-doc.org/core-1.9.3/Process.html#method-c-exit
330
+ Process.exit
331
+ end
332
+ end
333
+ end
334
+ end
@@ -0,0 +1,66 @@
1
+ module Framework
2
+ class Tree
3
+ attr_reader :headers_path
4
+ attr_reader :module_map_path
5
+ attr_reader :resources_path
6
+ attr_reader :root_path
7
+ attr_reader :versions_path
8
+
9
+ def delete_resources
10
+ Pathname.new(@resources_path).rmtree
11
+ (Pathname.new(@fwk_path) + Pathname.new('Resources')).delete
12
+ end
13
+
14
+ def initialize(name, platform, embedded)
15
+ @name = name
16
+ @platform = platform
17
+ @embedded = embedded
18
+ end
19
+
20
+ def make
21
+ make_root
22
+ make_framework
23
+ make_headers
24
+ make_resources
25
+ make_current_version
26
+ end
27
+
28
+ private
29
+
30
+ def make_current_version
31
+ current_version_path = @versions_path + Pathname.new('../Current')
32
+ `ln -sf A #{current_version_path}`
33
+ `ln -sf Versions/Current/Headers #{@fwk_path}/`
34
+ `ln -sf Versions/Current/Resources #{@fwk_path}/`
35
+ `ln -sf Versions/Current/#{@name} #{@fwk_path}/`
36
+ end
37
+
38
+ def make_framework
39
+ @fwk_path = @root_path + Pathname.new(@name + '.framework')
40
+ @fwk_path.mkdir unless @fwk_path.exist?
41
+
42
+ @module_map_path = @fwk_path + Pathname.new('Modules')
43
+ @versions_path = @fwk_path + Pathname.new('Versions/A')
44
+ end
45
+
46
+ def make_headers
47
+ @headers_path = @versions_path + Pathname.new('Headers')
48
+ @headers_path.mkpath unless @headers_path.exist?
49
+ end
50
+
51
+ def make_resources
52
+ @resources_path = @versions_path + Pathname.new('Resources')
53
+ @resources_path.mkpath unless @resources_path.exist?
54
+ end
55
+
56
+ def make_root
57
+ @root_path = Pathname.new(@platform)
58
+
59
+ if @embedded
60
+ @root_path += Pathname.new(@name + '.embeddedframework')
61
+ end
62
+
63
+ @root_path.mkpath unless @root_path.exist?
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,32 @@
1
+ module Symbols
2
+ #
3
+ # performs symbol aliasing
4
+ #
5
+ # for each dependency:
6
+ # - determine symbols for classes and global constants
7
+ # - alias each symbol to Pod#{pod_name}_#{symbol}
8
+ # - put defines into `GCC_PREPROCESSOR_DEFINITIONS` for passing to Xcode
9
+ #
10
+ def mangle_for_pod_dependencies(pod_name, sandbox_root)
11
+ pod_libs = Dir.glob("#{sandbox_root}/build/lib*.a").select do |file|
12
+ file !~ /lib#{pod_name}.a$/
13
+ end
14
+
15
+ dummy_alias = alias_symbol "PodsDummy_#{pod_name}", pod_name
16
+ all_syms = [dummy_alias]
17
+
18
+ pod_libs.each do |pod_lib|
19
+ syms = Symbols.symbols_from_library(pod_lib)
20
+ all_syms += syms.map! { |sym| alias_symbol sym, pod_name }
21
+ end
22
+
23
+ "GCC_PREPROCESSOR_DEFINITIONS='$(inherited) #{all_syms.uniq.join(' ')}'"
24
+ end
25
+
26
+ def alias_symbol(sym, pod_name)
27
+ pod_name = pod_name.tr('-', '_')
28
+ sym + "=Pod#{pod_name}_" + sym
29
+ end
30
+
31
+ module_function :mangle_for_pod_dependencies, :alias_symbol
32
+ end
@@ -0,0 +1,250 @@
1
+ module Pod
2
+ class Command
3
+ class Package < Command
4
+ private
5
+
6
+ def build_static_sandbox(dynamic)
7
+ static_sandbox_root = if dynamic
8
+ Pathname.new(config.sandbox_root + '/Static')
9
+ else
10
+ Pathname.new(config.sandbox_root)
11
+ end
12
+ Sandbox.new(static_sandbox_root)
13
+ end
14
+
15
+ def install_pod(platform_name, sandbox)
16
+ podfile = podfile_from_spec(
17
+ @path,
18
+ @spec.name,
19
+ platform_name,
20
+ @spec.deployment_target(platform_name),
21
+ @subspecs,
22
+ @spec_sources
23
+ )
24
+
25
+ static_installer = Installer.new(sandbox, podfile)
26
+ static_installer.install!
27
+
28
+ unless static_installer.nil?
29
+ static_installer.pods_project.targets.each do |target|
30
+ target.build_configurations.each do |config|
31
+ config.build_settings['CLANG_MODULES_AUTOLINK'] = 'NO'
32
+ config.build_settings['GCC_GENERATE_DEBUGGING_SYMBOLS'] = 'NO'
33
+ # 临时屏蔽模拟器arm64,后续应切换为xcframework格式以同时支持真机和模拟器arm64
34
+ config.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = 'arm64'
35
+ # 如下解决签名报错问题
36
+ config.build_settings['EXPANDED_CODE_SIGN_IDENTITY'] = ""
37
+ config.build_settings['CODE_SIGNING_REQUIRED'] = "NO"
38
+ config.build_settings['CODE_SIGNING_ALLOWED'] = "NO"
39
+ end
40
+ end
41
+ static_installer.pods_project.save
42
+ end
43
+
44
+ static_installer
45
+ end
46
+
47
+ def podfile_from_spec(path, spec_name, platform_name, deployment_target, subspecs, sources)
48
+ options = {}
49
+ if path
50
+ if @local
51
+ options[:path] = path
52
+ else
53
+ options[:podspec] = path
54
+ end
55
+ end
56
+ options[:subspecs] = subspecs if subspecs
57
+ Pod::Podfile.new do
58
+ sources.each { |s| source s }
59
+ platform(platform_name, deployment_target)
60
+ pod(spec_name, options)
61
+
62
+ install!('cocoapods',
63
+ :integrate_targets => false,
64
+ :deterministic_uuids => false)
65
+
66
+ target('packager') do
67
+ inherit! :complete
68
+ end
69
+ end
70
+ end
71
+
72
+ def binary_only?(spec)
73
+ deps = spec.dependencies.map { |dep| spec_with_name(dep.name) }
74
+ [spec, *deps].each do |specification|
75
+ %w(vendored_frameworks vendored_libraries).each do |attrib|
76
+ if specification.attributes_hash[attrib]
77
+ return true
78
+ end
79
+ end
80
+ end
81
+
82
+ false
83
+ end
84
+
85
+ def spec_with_name(name)
86
+ return if name.nil?
87
+
88
+ set = Pod::Config.instance.sources_manager.search(Dependency.new(name))
89
+ return nil if set.nil?
90
+
91
+ set.specification.root
92
+ end
93
+
94
+ def spec_with_path(path)
95
+ return if path.nil?
96
+ path = Pathname.new(path)
97
+ path = Pathname.new(Dir.pwd).join(path) unless path.absolute?
98
+ return unless path.exist?
99
+
100
+ @path = path.expand_path
101
+
102
+ if @path.directory?
103
+ help! @path + ': is a directory.'
104
+ return
105
+ end
106
+
107
+ unless ['.podspec', '.json'].include? @path.extname
108
+ help! @path + ': is not a podspec.'
109
+ return
110
+ end
111
+
112
+ Specification.from_file(@path)
113
+ end
114
+
115
+ #----------------------
116
+ # Dynamic Project Setup
117
+ #----------------------
118
+
119
+ def build_dynamic_sandbox(_static_sandbox, _static_installer)
120
+ dynamic_sandbox_root = Pathname.new(config.sandbox_root + '/Dynamic')
121
+ dynamic_sandbox = Sandbox.new(dynamic_sandbox_root)
122
+
123
+ dynamic_sandbox
124
+ end
125
+
126
+ # @param [Pod::Sandbox] dynamic_sandbox
127
+ #
128
+ # @param [Pod::Sandbox] static_sandbox
129
+ #
130
+ # @param [Pod::Installer] static_installer
131
+ #
132
+ # @param [Pod::Platform] platform
133
+ #
134
+ def install_dynamic_pod(dynamic_sandbox, static_sandbox, static_installer, platform)
135
+ # 1 Create a dynamic target for only the spec pod.
136
+ dynamic_target = build_dynamic_target(dynamic_sandbox, static_installer, platform)
137
+
138
+ # 2. Build a new xcodeproj in the dynamic_sandbox with only the spec pod as a target.
139
+ project = prepare_pods_project(dynamic_sandbox, dynamic_target.name, static_installer)
140
+
141
+ # 3. Copy the source directory for the dynamic framework from the static sandbox.
142
+ copy_dynamic_target(static_sandbox, dynamic_target, dynamic_sandbox)
143
+
144
+ # 4. Create the file references.
145
+ install_file_references(dynamic_sandbox, [dynamic_target], project)
146
+
147
+ # 5. Install the target.
148
+ install_library(dynamic_sandbox, dynamic_target, project)
149
+
150
+ # 6. Write the actual .xcodeproj to the dynamic sandbox.
151
+ write_pod_project(project, dynamic_sandbox)
152
+ end
153
+
154
+ # @param [Pod::Installer] static_installer
155
+ #
156
+ # @return [Pod::PodTarget]
157
+ #
158
+ def build_dynamic_target(dynamic_sandbox, static_installer, platform)
159
+ spec_targets = static_installer.pod_targets.select do |target|
160
+ target.name == @spec.name
161
+ end
162
+ static_target = spec_targets[0]
163
+
164
+ file_accessors = create_file_accessors(static_target, dynamic_sandbox)
165
+
166
+ archs = []
167
+ dynamic_target = Pod::PodTarget.new(dynamic_sandbox, true, static_target.user_build_configurations, archs, platform, static_target.specs, static_target.target_definitions, file_accessors)
168
+ dynamic_target
169
+ end
170
+
171
+ # @param [Pod::Sandbox] dynamic_sandbox
172
+ #
173
+ # @param [String] spec_name
174
+ #
175
+ # @param [Pod::Installer] installer
176
+ #
177
+ def prepare_pods_project(dynamic_sandbox, spec_name, installer)
178
+ # Create a new pods project
179
+ pods_project = Pod::Project.new(dynamic_sandbox.project_path)
180
+
181
+ # Update build configurations
182
+ installer.analysis_result.all_user_build_configurations.each do |name, type|
183
+ pods_project.add_build_configuration(name, type)
184
+ end
185
+
186
+ # Add the pod group for only the dynamic framework
187
+ local = dynamic_sandbox.local?(spec_name)
188
+ path = dynamic_sandbox.pod_dir(spec_name)
189
+ was_absolute = dynamic_sandbox.local_path_was_absolute?(spec_name)
190
+ pods_project.add_pod_group(spec_name, path, local, was_absolute)
191
+ pods_project
192
+ end
193
+
194
+ def copy_dynamic_target(static_sandbox, _dynamic_target, dynamic_sandbox)
195
+ command = "cp -a #{static_sandbox.root}/#{@spec.name} #{dynamic_sandbox.root}"
196
+ `#{command}`
197
+ end
198
+
199
+ def create_file_accessors(target, dynamic_sandbox)
200
+ pod_root = dynamic_sandbox.pod_dir(target.root_spec.name)
201
+
202
+ path_list = Sandbox::PathList.new(pod_root)
203
+ target.specs.map do |spec|
204
+ Sandbox::FileAccessor.new(path_list, spec.consumer(target.platform))
205
+ end
206
+ end
207
+
208
+ def install_file_references(dynamic_sandbox, pod_targets, pods_project)
209
+ installer = Pod::Installer::Xcode::PodsProjectGenerator::FileReferencesInstaller.new(dynamic_sandbox, pod_targets, pods_project)
210
+ installer.install!
211
+ end
212
+
213
+ def install_library(dynamic_sandbox, dynamic_target, project)
214
+ return if dynamic_target.target_definitions.flat_map(&:dependencies).empty?
215
+ target_installer = Pod::Installer::Xcode::PodsProjectGenerator::PodTargetInstaller.new(dynamic_sandbox, project, dynamic_target)
216
+ result = target_installer.install!
217
+ native_target = result.native_target
218
+
219
+ # Installs System Frameworks
220
+ if dynamic_target.should_build?
221
+ dynamic_target.file_accessors.each do |file_accessor|
222
+ file_accessor.spec_consumer.frameworks.each do |framework|
223
+ native_target.add_system_framework(framework)
224
+ end
225
+ file_accessor.spec_consumer.libraries.each do |library|
226
+ native_target.add_system_library(library)
227
+ end
228
+ end
229
+ end
230
+ end
231
+
232
+ def write_pod_project(dynamic_project, dynamic_sandbox)
233
+ UI.message "- Writing Xcode project file to #{UI.path dynamic_sandbox.project_path}" do
234
+ dynamic_project.pods.remove_from_project if dynamic_project.pods.empty?
235
+ dynamic_project.development_pods.remove_from_project if dynamic_project.development_pods.empty?
236
+ dynamic_project.sort(:groups_position => :below)
237
+ dynamic_project.recreate_user_schemes(false)
238
+
239
+ # Edit search paths so that we can find our dependency headers
240
+ dynamic_project.targets.first.build_configuration_list.build_configurations.each do |config|
241
+ config.build_settings['HEADER_SEARCH_PATHS'] = "$(inherited) #{Dir.pwd}/Pods/Static/Headers/**"
242
+ config.build_settings['USER_HEADER_SEARCH_PATHS'] = "$(inherited) #{Dir.pwd}/Pods/Static/Headers/**"
243
+ config.build_settings['OTHER_LDFLAGS'] = '$(inherited) -ObjC'
244
+ end
245
+ dynamic_project.save
246
+ end
247
+ end
248
+ end
249
+ end
250
+ end