cocoapods-precompile 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,41 @@
1
+ require_relative '../tool/tool'
2
+
3
+ module Pod
4
+ class Prebuild
5
+
6
+ # Pass the data between the 2 steps
7
+ #
8
+ # At step 2, the normal pod install, it needs some info of the
9
+ # prebuilt step. So we store it here.
10
+ #
11
+ class Passer
12
+
13
+ # indicate the add/remove/update of prebuit pods
14
+ # @return [Analyzer::SpecsState]
15
+ #
16
+ class_attr_accessor :prebuild_pods_changes
17
+
18
+
19
+ # represent the path of resurces to copy
20
+ class ResourcePath
21
+ attr_accessor :real_file_path
22
+ attr_accessor :target_file_path
23
+ end
24
+ # Save the resoures for static framework, and used when installing the prebuild framework
25
+ # static framework needs copy the resurces mannully
26
+ #
27
+ # @return [Hash<String, [Passer::ResourcePath]>]
28
+ class_attr_accessor :resources_to_copy_for_static_framework
29
+ self.resources_to_copy_for_static_framework = {}
30
+
31
+ # Some pod won't be build in prebuild stage even if it have `binary=>true`.
32
+ # The targets of this pods have `oshould_build? == true`.
33
+ # We should skip integration (patch spec) for this pods
34
+ #
35
+ # @return [Array<String>]
36
+ class_attr_accessor :target_names_to_skip_integration_framework
37
+ self.target_names_to_skip_integration_framework = []
38
+
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,130 @@
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
+
15
+ should_prebuild = Pod::Podfile::DSL.prebuild_all
16
+
17
+ options = requirements.last
18
+ if options.is_a?(Hash) && options[Pod::Prebuild.keyword] != nil
19
+ should_prebuild = options.delete(Pod::Prebuild.keyword)
20
+ requirements.pop if options.empty?
21
+ end
22
+
23
+ pod_name = Specification.root_name(name)
24
+ set_prebuild_for_pod(pod_name, should_prebuild)
25
+ end
26
+
27
+ def set_prebuild_for_pod(pod_name, should_prebuild)
28
+
29
+ if should_prebuild == true
30
+ @prebuild_framework_pod_names ||= []
31
+ @prebuild_framework_pod_names.push pod_name
32
+ else
33
+ @should_not_prebuild_framework_pod_names ||= []
34
+ @should_not_prebuild_framework_pod_names.push pod_name
35
+ end
36
+ end
37
+
38
+ def prebuild_framework_pod_names
39
+ names = @prebuild_framework_pod_names || []
40
+ if parent != nil and parent.kind_of? TargetDefinition
41
+ names += parent.prebuild_framework_pod_names
42
+ end
43
+ names
44
+ end
45
+ def should_not_prebuild_framework_pod_names
46
+ names = @should_not_prebuild_framework_pod_names || []
47
+ if parent != nil and parent.kind_of? TargetDefinition
48
+ names += parent.should_not_prebuild_framework_pod_names
49
+ end
50
+ names
51
+ end
52
+
53
+ # ---- patch method ----
54
+ # We want modify `store_pod` method, but it's hard to insert a line in the
55
+ # implementation. So we patch a method called in `store_pod`.
56
+ old_method = instance_method(:parse_inhibit_warnings)
57
+
58
+ define_method(:parse_inhibit_warnings) do |name, requirements|
59
+ parse_prebuild_framework(name, requirements)
60
+ old_method.bind(self).(name, requirements)
61
+ end
62
+
63
+ end
64
+ end
65
+ end
66
+
67
+
68
+ module Pod
69
+ class Installer
70
+
71
+ def prebuild_pod_targets
72
+ @prebuild_pod_targets ||= (
73
+ all = []
74
+
75
+ aggregate_targets = self.aggregate_targets
76
+ aggregate_targets.each do |aggregate_target|
77
+ target_definition = aggregate_target.target_definition
78
+ targets = aggregate_target.pod_targets || []
79
+
80
+ # filter prebuild
81
+ prebuild_names = target_definition.prebuild_framework_pod_names
82
+ if not Podfile::DSL.prebuild_all
83
+ targets = targets.select { |pod_target| prebuild_names.include?(pod_target.pod_name) }
84
+ end
85
+ dependency_targets = targets.map {|t| t.recursive_dependent_targets }.flatten.uniq || []
86
+ targets = (targets + dependency_targets).uniq
87
+
88
+ # filter should not prebuild
89
+ explict_should_not_names = target_definition.should_not_prebuild_framework_pod_names
90
+ targets = targets.reject { |pod_target| explict_should_not_names.include?(pod_target.pod_name) }
91
+
92
+ all += targets
93
+ end
94
+
95
+ all = all.reject {|pod_target| sandbox.local?(pod_target.pod_name) }
96
+ all.uniq
97
+ )
98
+ end
99
+
100
+ # the root names who needs prebuild, including dependency pods.
101
+ def prebuild_pod_names
102
+ @prebuild_pod_names ||= self.prebuild_pod_targets.map(&:pod_name)
103
+ end
104
+
105
+
106
+ def validate_every_pod_only_have_one_form
107
+
108
+ multi_targets_pods = self.pod_targets.group_by do |t|
109
+ t.pod_name
110
+ end.select do |k, v|
111
+ v.map{|t| t.platform.name }.count > 1
112
+ end
113
+
114
+ multi_targets_pods = multi_targets_pods.reject do |name, targets|
115
+ contained = targets.map{|t| self.prebuild_pod_targets.include? t }
116
+ contained.uniq.count == 1 # all equal
117
+ end
118
+
119
+ return if multi_targets_pods.empty?
120
+
121
+ warnings = "One pod can only be prebuilt or not prebuilt. These pod have different forms in multiple targets:\n"
122
+ warnings += multi_targets_pods.map{|name, targets| " #{name}: #{targets.map{|t|t.platform.name}}"}.join("\n")
123
+ raise Informative, warnings
124
+ end
125
+
126
+ end
127
+ end
128
+
129
+
130
+
@@ -0,0 +1,73 @@
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
+
31
+ def exsited_framework_target_names
32
+ exsited_framework_name_pairs.map {|pair| pair[0]}.uniq
33
+ end
34
+ def exsited_framework_pod_names
35
+ exsited_framework_name_pairs.map {|pair| pair[1]}.uniq
36
+ end
37
+ def existed_target_names_for_pod_name(pod_name)
38
+ exsited_framework_name_pairs.select {|pair| pair[1] == pod_name }.map { |pair| pair[0]}
39
+ end
40
+
41
+
42
+
43
+ def save_pod_name_for_target(target)
44
+ folder = framework_folder_path_for_target_name(target.name)
45
+ return unless folder.exist?
46
+ flag_file_path = folder + "#{target.pod_name}.pod_name"
47
+ File.write(flag_file_path.to_s, "")
48
+ end
49
+
50
+
51
+ private
52
+
53
+ def pod_name_for_target_folder(target_folder_path)
54
+ name = Pathname.new(target_folder_path).children.find do |child|
55
+ child.to_s.end_with? ".pod_name"
56
+ end
57
+ name = name.basename(".pod_name").to_s unless name.nil?
58
+ name ||= Pathname.new(target_folder_path).basename.to_s # for compatibility with older version
59
+ end
60
+
61
+ # Array<[target_name, pod_name]>
62
+ def exsited_framework_name_pairs
63
+ return [] unless generate_framework_path.exist?
64
+ generate_framework_path.children().map do |framework_path|
65
+ if framework_path.directory? && (not framework_path.children.empty?)
66
+ [framework_path.basename.to_s, pod_name_for_target_folder(framework_path)]
67
+ else
68
+ nil
69
+ end
70
+ end.reject(&:nil?).uniq
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,138 @@
1
+ require 'fourflusher'
2
+
3
+ CONFIGURATION = "Release"
4
+ PLATFORMS = { 'iphonesimulator' => 'iOS',
5
+ 'appletvsimulator' => 'tvOS',
6
+ 'watchsimulator' => 'watchOS' }
7
+
8
+ # Build specific target to framework file
9
+ # @param [PodTarget] target
10
+ # a specific pod target
11
+ #
12
+ def build_for_iosish_platform(sandbox,
13
+ build_dir,
14
+ output_path,
15
+ target,
16
+ device,
17
+ simulator,
18
+ bitcode_enabled,
19
+ simulator_default_arch)
20
+
21
+ deployment_target = target.platform.deployment_target.to_s
22
+
23
+ target_label = target.label # name with platform if it's used in multiple platforms
24
+ Pod::UI.puts "Prebuilding #{target_label}..."
25
+
26
+ other_options = []
27
+ if bitcode_enabled
28
+ other_options += ['OTHER_CFLAGS="-fembed-bitcode"']
29
+ end
30
+ xcodebuild(sandbox, target_label, device, deployment_target, other_options)
31
+ xcodebuild(sandbox, target_label, simulator, deployment_target, other_options + ["ARCHS=#{simulator_default_arch}",'ONLY_ACTIVE_ARCH=NO'])
32
+
33
+ # paths
34
+ target_name = target.name # equals target.label, like "AFNeworking-iOS" when AFNetworking is used in multiple platforms.
35
+ module_name = target.product_module_name
36
+ device_framwork_path = "#{build_dir}/#{CONFIGURATION}-#{device}/#{target_name}/#{module_name}.framework"
37
+ simulator_framwork_path = "#{build_dir}/#{CONFIGURATION}-#{simulator}/#{target_name}/#{module_name}.framework"
38
+
39
+ device_binary = device_framwork_path + "/#{module_name}"
40
+ simulator_binary = simulator_framwork_path + "/#{module_name}"
41
+ return unless File.file?(device_binary) && File.file?(simulator_binary)
42
+
43
+ # the device_lib path is the final output file path
44
+ # combine the bianries
45
+ tmp_lipoed_binary_path = "#{build_dir}/#{target_name}"
46
+ lipo_log = `lipo -create -output #{tmp_lipoed_binary_path} #{device_binary} #{simulator_binary}`
47
+ puts lipo_log unless File.exist?(tmp_lipoed_binary_path)
48
+ FileUtils.mv tmp_lipoed_binary_path, device_binary, :force => true
49
+
50
+ # collect the swiftmodule file for various archs.
51
+ device_swiftmodule_path = device_framwork_path + "/Modules/#{module_name}.swiftmodule"
52
+ simulator_swiftmodule_path = simulator_framwork_path + "/Modules/#{module_name}.swiftmodule"
53
+ if File.exist?(device_swiftmodule_path)
54
+ FileUtils.cp_r simulator_swiftmodule_path + "/.", device_swiftmodule_path
55
+ end
56
+
57
+ # output
58
+ output_path.mkpath unless output_path.exist?
59
+ FileUtils.mv device_framwork_path, output_path, :force => true
60
+
61
+ end
62
+
63
+ def xcodebuild(sandbox, target, sdk='macosx', deployment_target=nil, other_options=[])
64
+ args = %W(-project #{sandbox.project_path.realdirpath} -scheme #{target} -configuration #{CONFIGURATION} -sdk #{sdk} )
65
+ platform = PLATFORMS[sdk]
66
+ args += Fourflusher::SimControl.new.destination(:oldest, platform, deployment_target) unless platform.nil?
67
+ args += other_options
68
+ Pod::Executable.execute_command 'xcodebuild', args, true
69
+ end
70
+
71
+
72
+
73
+ module Pod
74
+ class Prebuild
75
+
76
+ # Build the frameworks with sandbox and targets
77
+ #
78
+ # @param [String] sandbox_root_path
79
+ # The sandbox root path where the targets project place
80
+ #
81
+ # [PodTarget] target
82
+ # The pod targets to build
83
+ #
84
+ # [Pathname] output_path
85
+ # output path for generated frameworks
86
+ #
87
+ def self.build(sandbox_root_path, target, output_path, bitcode_enabled = false)
88
+
89
+ return unless not target == nil
90
+
91
+ sandbox_root = Pathname(sandbox_root_path)
92
+ sandbox = Pod::Sandbox.new(sandbox_root)
93
+ build_dir = self.build_dir(sandbox_root)
94
+
95
+ # -- build the framework
96
+ case target.platform.name
97
+ when :ios then build_for_iosish_platform(sandbox, build_dir, output_path, target, 'iphoneos', 'iphonesimulator', bitcode_enabled, "x86_64")
98
+ when :osx then xcodebuild(sandbox, target.label)
99
+ # when :tvos then build_for_iosish_platform(sandbox, build_dir, target, 'appletvos', 'appletvsimulator')
100
+ when :watchos then build_for_iosish_platform(sandbox, build_dir, output_path, target, 'watchos', 'watchsimulator', true, "i386")
101
+ else raise "Unsupported platform for '#{target.name}': '#{target.platform.name}'" end
102
+
103
+ raise Pod::Informative, 'The build directory was not found in the expected location.' unless build_dir.directory?
104
+
105
+ # # --- copy the vendored libraries and framework
106
+ # frameworks = build_dir.children.select{ |path| File.extname(path) == ".framework" }
107
+ # Pod::UI.puts "Built #{frameworks.count} #{'frameworks'.pluralize(frameworks.count)}"
108
+
109
+ # pod_target = target
110
+ # consumer = pod_target.root_spec.consumer(pod_target.platform.name)
111
+ # file_accessor = Pod::Sandbox::FileAccessor.new(sandbox.pod_dir(pod_target.pod_name), consumer)
112
+ # frameworks += file_accessor.vendored_libraries
113
+ # frameworks += file_accessor.vendored_frameworks
114
+
115
+ # frameworks.uniq!
116
+
117
+ # frameworks.each do |framework|
118
+ # FileUtils.mkdir_p destination
119
+ # FileUtils.cp_r framework, destination, :remove_destination => true
120
+ # end
121
+ # build_dir.rmtree if build_dir.directory?
122
+ end
123
+
124
+ def self.remove_build_dir(sandbox_root)
125
+ path = build_dir(sandbox_root)
126
+ path.rmtree if path.exist?
127
+ end
128
+
129
+ private
130
+
131
+ def self.build_dir(sandbox_root)
132
+ # don't know why xcode chose this folder
133
+ sandbox_root.parent + 'build'
134
+ end
135
+
136
+ end
137
+ end
138
+
@@ -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/gem_version'
@@ -0,0 +1,2 @@
1
+ require 'cocoapods-binary/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
+ #-----------------------------------------------------------------------------#