cocoapods-binary-bel 0.5.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.
@@ -0,0 +1,139 @@
1
+ module Pod
2
+
3
+ class Prebuild
4
+ def self.keyword
5
+ :binary
6
+ end
7
+ end
8
+
9
+ class Podfile
10
+ class TargetDefinition
11
+
12
+ ## --- option for setting using prebuild framework ---
13
+ def parse_prebuild_framework(name, requirements)
14
+ should_prebuild = Pod::Podfile::DSL.prebuild_all && (not Pod::Podfile::DSL.framework_source_all)
15
+
16
+ options = requirements.last
17
+ if options.is_a?(Hash) && options[Pod::Prebuild.keyword] != nil
18
+ should_prebuild = options.delete(Pod::Prebuild.keyword) && (not Pod::Podfile::DSL.framework_source_all)
19
+ requirements.pop if options.empty?
20
+ end
21
+
22
+ if Pod::Command::Install.all_use_source
23
+ should_prebuild = false
24
+ end
25
+
26
+ pod_name = Specification.root_name(name)
27
+ set_prebuild_for_pod(pod_name, should_prebuild)
28
+ end
29
+
30
+ def set_prebuild_for_pod(pod_name, should_prebuild)
31
+
32
+ if should_prebuild == true
33
+ @prebuild_framework_pod_names ||= []
34
+ @prebuild_framework_pod_names.push pod_name
35
+ elsif should_prebuild == false
36
+ @should_not_prebuild_framework_pod_names ||= []
37
+ @should_not_prebuild_framework_pod_names.push pod_name
38
+ end
39
+ end
40
+
41
+ def prebuild_framework_pod_names
42
+ names = @prebuild_framework_pod_names || []
43
+ if parent != nil and parent.kind_of? TargetDefinition
44
+ names += parent.prebuild_framework_pod_names
45
+ end
46
+ names
47
+ end
48
+ def should_not_prebuild_framework_pod_names
49
+ names = @should_not_prebuild_framework_pod_names || []
50
+ if parent != nil and parent.kind_of? TargetDefinition
51
+ names += parent.should_not_prebuild_framework_pod_names
52
+ end
53
+ names
54
+ end
55
+
56
+ # ---- patch method ----
57
+ # We want modify `store_pod` method, but it's hard to insert a line in the
58
+ # implementation. So we patch a method called in `store_pod`.
59
+ old_method = instance_method(:parse_inhibit_warnings)
60
+
61
+ define_method(:parse_inhibit_warnings) do |name, requirements|
62
+ variables = requirements
63
+ parse_prebuild_framework(name, requirements)
64
+ old_method.bind(self).(name, variables)
65
+ end
66
+
67
+ end
68
+ end
69
+ end
70
+
71
+
72
+ module Pod
73
+ class Installer
74
+
75
+ def prebuild_pod_targets
76
+ @prebuild_pod_targets ||= (
77
+ all = []
78
+
79
+ aggregate_targets = self.aggregate_targets
80
+ aggregate_targets.each do |aggregate_target|
81
+ target_definition = aggregate_target.target_definition
82
+ targets = aggregate_target.pod_targets || []
83
+ # filter prebuild
84
+ prebuild_names = target_definition.prebuild_framework_pod_names
85
+ if not Podfile::DSL.prebuild_all
86
+ targets = targets.select { |pod_target| prebuild_names.include?(pod_target.pod_name) }
87
+ end
88
+
89
+ dependency_targets = targets.map {|t| t.recursive_dependent_targets }.flatten.uniq || []
90
+
91
+ targets = (targets + dependency_targets).uniq
92
+ # filter should not prebuild
93
+ explict_should_not_names = target_definition.should_not_prebuild_framework_pod_names
94
+ Pod::UI.puts(">>>>>>> 不需要二进制的framework: #{explict_should_not_names} ") if config.verbose
95
+ targets = targets.reject { |pod_target| explict_should_not_names.include?(pod_target.pod_name) }
96
+
97
+ all += targets
98
+
99
+ end
100
+ all = all.reject {|pod_target| sandbox.local?(pod_target.pod_name) }
101
+ Pod::UI.puts(">>>>>>> 需要二进制的framework: #{all}") if config.verbose
102
+ all.uniq
103
+
104
+
105
+
106
+ )
107
+ end
108
+
109
+ # the root names who needs prebuild, including dependency pods.
110
+ def prebuild_pod_names
111
+ @prebuild_pod_names ||= self.prebuild_pod_targets.map(&:pod_name)
112
+ end
113
+
114
+
115
+ def validate_every_pod_only_have_one_form
116
+
117
+ multi_targets_pods = self.pod_targets.group_by do |t|
118
+ t.pod_name
119
+ end.select do |k, v|
120
+ v.map{|t| t.platform.name }.count > 1
121
+ end
122
+
123
+ multi_targets_pods = multi_targets_pods.reject do |name, targets|
124
+ contained = targets.map{|t| self.prebuild_pod_targets.include? t }
125
+ contained.uniq.count == 1 # all equal
126
+ end
127
+
128
+ return if multi_targets_pods.empty?
129
+
130
+ warnings = "One pod can only be prebuilt or not prebuilt. These pod have different forms in multiple targets:\n"
131
+ warnings += multi_targets_pods.map{|name, targets| " #{name}: #{targets.map{|t|t.platform.name}}"}.join("\n")
132
+ raise Informative, warnings
133
+ end
134
+
135
+ end
136
+ end
137
+
138
+
139
+
@@ -0,0 +1,82 @@
1
+ require_relative "names"
2
+
3
+ module Pod
4
+ class PrebuildSandbox < Sandbox
5
+
6
+ # [String] standard_sandbox_path
7
+ def self.from_standard_sanbox_path(path)
8
+ prebuild_sandbox_path = Pathname.new(path).realpath + "_Prebuild"
9
+ self.new(prebuild_sandbox_path)
10
+ end
11
+
12
+ def self.from_standard_sandbox(sandbox)
13
+ self.from_standard_sanbox_path(sandbox.root)
14
+ end
15
+
16
+ def standard_sanbox_path
17
+ self.root.parent
18
+ end
19
+
20
+ def generate_framework_path
21
+ self.root + "GeneratedFrameworks"
22
+ end
23
+
24
+ # @param name [String] pass the target.name (may containing platform suffix)
25
+ # @return [Pathname] the folder containing the framework file.
26
+ def framework_folder_path_for_target_name(name)
27
+ self.generate_framework_path + name
28
+ end
29
+
30
+ def plist_path_for_target_name(name)
31
+ framework_path = framework_folder_path_for_target_name(name)
32
+ "#{framework_path}/#{name}.framework/Info.plist"
33
+ end
34
+
35
+ def source_framework_path(name)
36
+ self.root + name
37
+ end
38
+
39
+
40
+ def exsited_framework_target_names
41
+ exsited_framework_name_pairs.map {|pair| pair[0]}.uniq
42
+ end
43
+ def exsited_framework_pod_names
44
+ exsited_framework_name_pairs.map {|pair| pair[1]}.uniq
45
+ end
46
+ def existed_target_names_for_pod_name(pod_name)
47
+ exsited_framework_name_pairs.select {|pair| pair[1] == pod_name }.map { |pair| pair[0]}
48
+ end
49
+
50
+
51
+
52
+ def save_pod_name_for_target(target)
53
+ folder = framework_folder_path_for_target_name(target.name)
54
+ return unless folder.exist?
55
+ flag_file_path = folder + "#{target.pod_name}.pod_name"
56
+ File.write(flag_file_path.to_s, "")
57
+ end
58
+
59
+
60
+ private
61
+
62
+ def pod_name_for_target_folder(target_folder_path)
63
+ name = Pathname.new(target_folder_path).children.find do |child|
64
+ child.to_s.end_with? ".pod_name"
65
+ end
66
+ name = name.basename(".pod_name").to_s unless name.nil?
67
+ name ||= Pathname.new(target_folder_path).basename.to_s # for compatibility with older version
68
+ end
69
+
70
+ # Array<[target_name, pod_name]>
71
+ def exsited_framework_name_pairs
72
+ return [] unless generate_framework_path.exist?
73
+ generate_framework_path.children().map do |framework_path|
74
+ if framework_path.directory? && (not framework_path.children.empty?)
75
+ [framework_path.basename.to_s, pod_name_for_target_folder(framework_path)]
76
+ else
77
+ nil
78
+ end
79
+ end.reject(&:nil?).uniq
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,49 @@
1
+
2
+ module Pod
3
+ class Prebuild
4
+
5
+ # Check the targets, for the current limitation of the plugin
6
+ #
7
+ # @param [Array<PodTarget>] prebuilt_targets
8
+ def self.check_one_pod_should_have_only_one_target(prebuilt_targets)
9
+
10
+ targets_have_different_platforms = prebuilt_targets.select {|t| t.pod_name != t.name }
11
+
12
+ if targets_have_different_platforms.count > 0
13
+ names = targets_have_different_platforms.map(&:pod_name)
14
+ raw_names = targets_have_different_platforms.map(&:name)
15
+ message = "Oops, you came across a limitation of cocoapods-binary-bel.
16
+
17
+ The plugin requires that one pod should have ONLY ONE target in the 'Pod.xcodeproj'. There are mainly 2 situations \
18
+ causing this problem:
19
+
20
+ 1. One pod integrates in 2 or more different platforms' targets. e.g.
21
+ ```
22
+ target 'iphoneApp' do
23
+ pod 'A', :binary => true
24
+ end
25
+ target 'watchApp' do
26
+ pod 'A'
27
+ end
28
+ ```
29
+
30
+ 2. Use different subspecs in multiple targets. e.g.
31
+ ```
32
+ target 'iphoneApp' do
33
+ pod 'A/core'
34
+ pod 'A/network'
35
+ end
36
+ target 'iphoneAppTest' do
37
+ pod 'A/core'
38
+ end
39
+ ```
40
+
41
+ Related pods: #{names}, target names: #{raw_names}
42
+ "
43
+ raise Informative, message
44
+ end
45
+ end
46
+
47
+
48
+ end
49
+ end
@@ -0,0 +1,203 @@
1
+ require 'fourflusher'
2
+ require 'xcpretty'
3
+
4
+ CONFIGURATION = "Debug"
5
+ PLATFORMS = { 'iphonesimulator' => 'iOS',
6
+ 'appletvsimulator' => 'tvOS',
7
+ 'watchsimulator' => 'watchOS' }
8
+
9
+ # Build specific target to framework file
10
+ # @param [PodTarget] target
11
+ # a specific pod target
12
+ #
13
+ def build_for_iosish_platform(sandbox,
14
+ build_dir,
15
+ output_path,
16
+ target,
17
+ device,
18
+ simulator,
19
+ bitcode_enabled,
20
+ custom_build_options = [], # Array<String>
21
+ custom_build_options_simulator = [] # Array<String>
22
+ )
23
+
24
+ deployment_target = target.platform.deployment_target.to_s
25
+
26
+ target_label = target.label # name with platform if it's used in multiple platforms
27
+ Pod::UI.puts "Prebuilding #{target_label}..."
28
+
29
+ other_options = []
30
+ # bitcode enabled
31
+ other_options += ['BITCODE_GENERATION_MODE=bitcode'] if bitcode_enabled
32
+ # make less arch to iphone simulator for faster build
33
+ custom_build_options_simulator += ['ARCHS=x86_64', 'ONLY_ACTIVE_ARCH=NO'] if simulator == 'iphonesimulator'
34
+
35
+ is_succeed, _ = xcodebuild(sandbox, target_label, device, deployment_target, other_options + custom_build_options)
36
+ exit 1 unless is_succeed
37
+ is_succeed, _ = xcodebuild(sandbox, target_label, simulator, deployment_target, other_options + custom_build_options_simulator)
38
+ exit 1 unless is_succeed
39
+
40
+ # paths
41
+ target_name = target.name # equals target.label, like "AFNeworking-iOS" when AFNetworking is used in multiple platforms.
42
+ module_name = target.product_module_name
43
+ device_framework_path = "#{build_dir}/#{CONFIGURATION}-#{device}/#{target_name}/#{module_name}.framework"
44
+ simulator_framework_path = "#{build_dir}/#{CONFIGURATION}-#{simulator}/#{target_name}/#{module_name}.framework"
45
+
46
+ device_binary = device_framework_path + "/#{module_name}"
47
+ simulator_binary = simulator_framework_path + "/#{module_name}"
48
+ return unless File.file?(device_binary) && File.file?(simulator_binary)
49
+
50
+ # the device_lib path is the final output file path
51
+ # combine the binaries
52
+ tmp_lipoed_binary_path = "#{build_dir}/#{target_name}"
53
+ lipo_log = `lipo -create -output #{tmp_lipoed_binary_path} #{device_binary} #{simulator_binary}`
54
+ puts lipo_log unless File.exist?(tmp_lipoed_binary_path)
55
+ FileUtils.mv tmp_lipoed_binary_path, device_binary, :force => true
56
+
57
+ # collect the swiftmodule file for various archs.
58
+ device_swiftmodule_path = device_framework_path + "/Modules/#{module_name}.swiftmodule"
59
+ simulator_swiftmodule_path = simulator_framework_path + "/Modules/#{module_name}.swiftmodule"
60
+ if File.exist?(device_swiftmodule_path)
61
+ FileUtils.cp_r simulator_swiftmodule_path + "/.", device_swiftmodule_path
62
+ end
63
+
64
+ # combine the generated swift headers
65
+ # (In xcode 10.2, the generated swift headers vary for each archs)
66
+ # https://github.com/leavez/cocoapods-binary/issues/58
67
+ simulator_generated_swift_header_path = simulator_framework_path + "/Headers/#{module_name}-Swift.h"
68
+ device_generated_swift_header_path = device_framework_path + "/Headers/#{module_name}-Swift.h"
69
+ if File.exist? simulator_generated_swift_header_path
70
+ device_header = File.read(device_generated_swift_header_path)
71
+ simulator_header = File.read(simulator_generated_swift_header_path)
72
+ # https://github.com/Carthage/Carthage/issues/2718#issuecomment-473870461
73
+ combined_header_content = %Q{
74
+ #if TARGET_OS_SIMULATOR // merged by cocoapods-binary-bel
75
+
76
+ #{simulator_header}
77
+
78
+ #else // merged by cocoapods-binary-bel
79
+
80
+ #{device_header}
81
+
82
+ #endif // merged by cocoapods-binary-bel
83
+ }
84
+ File.write(device_generated_swift_header_path, combined_header_content.strip)
85
+ end
86
+
87
+ # # handle the dSYM files
88
+ # device_dsym = "#{device_framework_path}.dSYM"
89
+ # if File.exist? device_dsym
90
+ # # lipo the simulator dsym
91
+ # simulator_dsym = "#{simulator_framework_path}.dSYM"
92
+ # if File.exist? simulator_dsym
93
+ # tmp_lipoed_binary_path = "#{output_path}/#{module_name}.draft"
94
+ # lipo_log = `lipo -create -output #{tmp_lipoed_binary_path} #{device_dsym}/Contents/Resources/DWARF/#{module_name} #{simulator_dsym}/Contents/Resources/DWARF/#{module_name}`
95
+ # puts lipo_log unless File.exist?(tmp_lipoed_binary_path)
96
+ # FileUtils.mv tmp_lipoed_binary_path, "#{device_framework_path}.dSYM/Contents/Resources/DWARF/#{module_name}", :force => true
97
+ # end
98
+ # # move
99
+ # FileUtils.mv device_dsym, output_path, :force => true
100
+ # end
101
+
102
+ # # output
103
+ output_path.mkpath unless output_path.exist?
104
+ FileUtils.mv device_framework_path, output_path, :force => true
105
+
106
+ end
107
+
108
+ def xcodebuild(sandbox, target, sdk='macosx', deployment_target=nil, other_options=[])
109
+ args = %W(-project #{sandbox.project_path.realdirpath} -scheme #{target} -configuration #{CONFIGURATION} -sdk #{sdk} )
110
+ platform = PLATFORMS[sdk]
111
+ args += Fourflusher::SimControl.new.destination(:oldest, platform, deployment_target) unless platform.nil?
112
+ args += other_options
113
+ log = `xcodebuild #{args.join(" ")} 2>&1`
114
+ exit_code = $?.exitstatus # Process::Status
115
+ is_succeed = (exit_code == 0)
116
+
117
+ if !is_succeed
118
+ Pod::UI.puts("xcodebuild failed exitstatus:#{exit_code}")
119
+ begin
120
+ if log.include?('** BUILD FAILED **')
121
+ # use xcpretty to print build log
122
+ # 64 represent command invalid. http://www.manpagez.com/man/3/sysexits/
123
+ printer = XCPretty::Printer.new({:formatter => XCPretty::Simple, :colorize => 'auto'})
124
+ log.each_line do |line|
125
+ printer.pretty_print(line)
126
+ end
127
+ else
128
+ raise "shouldn't be handle by xcpretty"
129
+ end
130
+ rescue
131
+ puts log.red
132
+ end
133
+ end
134
+ [is_succeed, log]
135
+ end
136
+
137
+
138
+
139
+ module Pod
140
+ class Prebuild
141
+
142
+ # Build the frameworks with sandbox and targets
143
+ #
144
+ # @param [String] sandbox_root_path
145
+ # The sandbox root path where the targets project place
146
+ #
147
+ # [PodTarget] target
148
+ # The pod targets to build
149
+ #
150
+ # [Pathname] output_path
151
+ # output path for generated frameworks
152
+ #
153
+ def self.build(sandbox_root_path, target, output_path, bitcode_enabled = false, custom_build_options=[], custom_build_options_simulator=[])
154
+
155
+ return if target.nil?
156
+
157
+ sandbox_root = Pathname(sandbox_root_path)
158
+ sandbox = Pod::Sandbox.new(sandbox_root)
159
+ build_dir = self.build_dir(sandbox_root)
160
+
161
+ # -- build the framework
162
+ case target.platform.name
163
+ when :ios then build_for_iosish_platform(sandbox, build_dir, output_path, target, 'iphoneos', 'iphonesimulator', bitcode_enabled, custom_build_options, custom_build_options_simulator)
164
+ when :osx then xcodebuild(sandbox, target.label, 'macosx', nil, custom_build_options)
165
+ # when :tvos then build_for_iosish_platform(sandbox, build_dir, target, 'appletvos', 'appletvsimulator')
166
+ when :watchos then build_for_iosish_platform(sandbox, build_dir, output_path, target, 'watchos', 'watchsimulator', true, custom_build_options, custom_build_options_simulator)
167
+ else raise "Unsupported platform for '#{target.name}': '#{target.platform.name}'" end
168
+
169
+ raise Pod::Informative, 'The build directory was not found in the expected location.' unless build_dir.directory?
170
+
171
+ # # --- copy the vendored libraries and framework
172
+ # frameworks = build_dir.children.select{ |path| File.extname(path) == ".framework" }
173
+ # Pod::UI.puts "Built #{frameworks.count} #{'frameworks'.pluralize(frameworks.count)}"
174
+
175
+ # pod_target = target
176
+ # consumer = pod_target.root_spec.consumer(pod_target.platform.name)
177
+ # file_accessor = Pod::Sandbox::FileAccessor.new(sandbox.pod_dir(pod_target.pod_name), consumer)
178
+ # frameworks += file_accessor.vendored_libraries
179
+ # frameworks += file_accessor.vendored_frameworks
180
+
181
+ # frameworks.uniq!
182
+
183
+ # frameworks.each do |framework|
184
+ # FileUtils.mkdir_p destination
185
+ # FileUtils.cp_r framework, destination, :remove_destination => true
186
+ # end
187
+ # build_dir.rmtree if build_dir.directory?
188
+ end
189
+
190
+ def self.remove_build_dir(sandbox_root)
191
+ path = build_dir(sandbox_root)
192
+ path.rmtree if path.exist?
193
+ end
194
+
195
+ private
196
+
197
+ def self.build_dir(sandbox_root)
198
+ # don't know why xcode chose this folder
199
+ sandbox_root.parent + 'build'
200
+ end
201
+
202
+ end
203
+ end
@@ -0,0 +1,12 @@
1
+ # attr_accessor for class variable.
2
+ # usage:
3
+ #
4
+ # ```
5
+ # class Pod
6
+ # class_attr_accessor :is_prebuild_stage
7
+ # end
8
+ # ```
9
+ #
10
+ def class_attr_accessor(symbol)
11
+ self.class.send(:attr_accessor, symbol)
12
+ end
@@ -0,0 +1 @@
1
+ require 'cocoapods-binary-bel/gem_version'
@@ -0,0 +1,2 @@
1
+ require 'cocoapods-binary-bel/Main'
2
+
@@ -0,0 +1,50 @@
1
+ require 'pathname'
2
+ ROOT = Pathname.new(File.expand_path('../../', __FILE__))
3
+ $:.unshift((ROOT + 'lib').to_s)
4
+ $:.unshift((ROOT + 'spec').to_s)
5
+
6
+ require 'bundler/setup'
7
+ require 'bacon'
8
+ require 'mocha-on-bacon'
9
+ require 'pretty_bacon'
10
+ require 'pathname'
11
+ require 'cocoapods'
12
+
13
+ Mocha::Configuration.prevent(:stubbing_non_existent_method)
14
+
15
+ require 'cocoapods_plugin'
16
+
17
+ #-----------------------------------------------------------------------------#
18
+
19
+ module Pod
20
+
21
+ # Disable the wrapping so the output is deterministic in the tests.
22
+ #
23
+ UI.disable_wrap = true
24
+
25
+ # Redirects the messages to an internal store.
26
+ #
27
+ module UI
28
+ @output = ''
29
+ @warnings = ''
30
+
31
+ class << self
32
+ attr_accessor :output
33
+ attr_accessor :warnings
34
+
35
+ def puts(message = '')
36
+ @output << "#{message}\n"
37
+ end
38
+
39
+ def warn(message = '', actions = [])
40
+ @warnings << "#{message}\n"
41
+ end
42
+
43
+ def print(message)
44
+ @output << message
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ #-----------------------------------------------------------------------------#