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,110 @@
1
+ # encoding: UTF-8
2
+ require_relative 'helper/podfile_options'
3
+ require_relative 'tool/tool'
4
+
5
+ module Pod
6
+ class Podfile
7
+ module DSL
8
+
9
+ # Enable prebuiding for all pods
10
+ # it has a lower priority to other binary settings
11
+ def all_binary!
12
+ DSL.prebuild_all = true
13
+ end
14
+
15
+ # Enable bitcode for prebuilt frameworks
16
+ def enable_bitcode_for_prebuilt_frameworks!
17
+ DSL.bitcode_enabled = true
18
+ end
19
+
20
+ # Don't remove source code of prebuilt pods
21
+ # It may speed up the pod install if git didn't
22
+ # include the `Pods` folder
23
+ def keep_source_code_for_prebuilt_frameworks!
24
+ DSL.dont_remove_source_code = true
25
+ end
26
+
27
+ private
28
+ class_attr_accessor :prebuild_all
29
+ prebuild_all = false
30
+
31
+ class_attr_accessor :bitcode_enabled
32
+ bitcode_enabled = false
33
+
34
+ class_attr_accessor :dont_remove_source_code
35
+ dont_remove_source_code = false
36
+ end
37
+ end
38
+ end
39
+
40
+ Pod::HooksManager.register('cocoapods-binary', :pre_install) do |installer_context|
41
+
42
+ require_relative 'helper/feature_switches'
43
+ if Pod.is_prebuild_stage
44
+ next
45
+ end
46
+
47
+ # [Check Environment]
48
+ # check user_framework is on
49
+ podfile = installer_context.podfile
50
+ podfile.target_definition_list.each do |target_definition|
51
+ next if target_definition.prebuild_framework_pod_names.empty?
52
+ if not target_definition.uses_frameworks?
53
+ STDERR.puts "[!] Cocoapods-binary requires `use_frameworks!`".red
54
+ exit
55
+ end
56
+ end
57
+
58
+
59
+ # -- step 1: prebuild framework ---
60
+ # Execute a sperated pod install, to generate targets for building framework,
61
+ # then compile them to framework files.
62
+ require_relative 'helper/prebuild_sandbox'
63
+ require_relative 'Prebuild'
64
+
65
+ Pod::UI.puts "🚀 Prebuild frameworks"
66
+
67
+
68
+ # control features
69
+ Pod.is_prebuild_stage = true
70
+ Pod::Podfile::DSL.enable_prebuild_patch true # enable sikpping for prebuild targets
71
+ Pod::Installer.force_disable_integration true # don't integrate targets
72
+ Pod::Config.force_disable_write_lockfile true # disbale write lock file for perbuild podfile
73
+ Pod::Installer.disable_install_complete_message true # disable install complete message
74
+
75
+ # make another custom sandbox
76
+ standard_sandbox = installer_context.sandbox
77
+ prebuild_sandbox = Pod::PrebuildSandbox.from_standard_sandbox(standard_sandbox)
78
+
79
+ # get the podfile for prebuild
80
+ prebuild_podfile = Pod::Podfile.from_ruby(podfile.defined_in_file)
81
+
82
+ # install
83
+ binary_installer = Pod::Installer.new(prebuild_sandbox, prebuild_podfile , nil)
84
+
85
+ if binary_installer.have_exact_prebuild_cache?
86
+ binary_installer.install_when_cache_hit!
87
+ else
88
+ binary_installer.repo_update = false
89
+ binary_installer.update = false
90
+ binary_installer.install!
91
+ end
92
+
93
+
94
+ # reset the environment
95
+ Pod.is_prebuild_stage = false
96
+ Pod::Installer.force_disable_integration false
97
+ Pod::Podfile::DSL.enable_prebuild_patch false
98
+ Pod::Config.force_disable_write_lockfile false
99
+ Pod::Installer.disable_install_complete_message false
100
+ Pod::UserInterface.warnings = [] # clean the warning in the prebuild step, it's duplicated.
101
+
102
+
103
+ # -- step 2: pod install ---
104
+ # install
105
+ Pod::UI.puts "\n"
106
+ Pod::UI.puts "🤖 Pod Install"
107
+ require_relative 'Integration'
108
+ # go on the normal install step ...
109
+ end
110
+
@@ -0,0 +1,212 @@
1
+ require_relative 'rome/build_framework'
2
+ require_relative 'helper/passer'
3
+
4
+ # patch prebuild ability
5
+ module Pod
6
+ class Installer
7
+
8
+
9
+ private
10
+
11
+ def local_manifest
12
+ if not @local_manifest_inited
13
+ @local_manifest_inited = true
14
+ raise "This method should be call before generate project" unless self.analysis_result == nil
15
+ @local_manifest = self.sandbox.manifest
16
+ end
17
+ @local_manifest
18
+ end
19
+
20
+ # @return [Analyzer::SpecsState]
21
+ def prebuild_pods_changes
22
+ return nil if local_manifest.nil?
23
+ if @prebuild_pods_changes.nil?
24
+ changes = local_manifest.detect_changes_with_podfile(podfile)
25
+ @prebuild_pods_changes = Analyzer::SpecsState.new(changes)
26
+ # save the chagnes info for later stage
27
+ Pod::Prebuild::Passer.prebuild_pods_changes = @prebuild_pods_changes
28
+ end
29
+ @prebuild_pods_changes
30
+ end
31
+
32
+
33
+ public
34
+
35
+ # check if need to prebuild
36
+ def have_exact_prebuild_cache?
37
+ # check if need build frameworks
38
+ return false if local_manifest == nil
39
+
40
+ changes = prebuild_pods_changes
41
+ added = changes.added
42
+ changed = changes.changed
43
+ unchanged = changes.unchanged
44
+ deleted = changes.deleted
45
+
46
+ exsited_framework_pod_names = sandbox.exsited_framework_pod_names
47
+ missing = unchanged.select do |pod_name|
48
+ not exsited_framework_pod_names.include?(pod_name)
49
+ end
50
+
51
+ needed = (added + changed + deleted + missing)
52
+ return needed.empty?
53
+ end
54
+
55
+
56
+ # The install method when have completed cache
57
+ def install_when_cache_hit!
58
+ # just print log
59
+ self.sandbox.exsited_framework_target_names.each do |name|
60
+ UI.puts "Using #{name}"
61
+ end
62
+ end
63
+
64
+
65
+ # Build the needed framework files
66
+ def prebuild_frameworks!
67
+
68
+ # build options
69
+ sandbox_path = sandbox.root
70
+ existed_framework_folder = sandbox.generate_framework_path
71
+ bitcode_enabled = Pod::Podfile::DSL.bitcode_enabled
72
+ targets = []
73
+
74
+ if local_manifest != nil
75
+
76
+ changes = prebuild_pods_changes
77
+ added = changes.added
78
+ changed = changes.changed
79
+ unchanged = changes.unchanged
80
+ deleted = changes.deleted
81
+
82
+ existed_framework_folder.mkdir unless existed_framework_folder.exist?
83
+ exsited_framework_pod_names = sandbox.exsited_framework_pod_names
84
+
85
+ # additions
86
+ missing = unchanged.select do |pod_name|
87
+ not exsited_framework_pod_names.include?(pod_name)
88
+ end
89
+
90
+
91
+ root_names_to_update = (added + changed + missing)
92
+
93
+ # transform names to targets
94
+ cache = []
95
+ targets = root_names_to_update.map do |pod_name|
96
+ Pod.fast_get_targets_for_pod_name(pod_name, self.pod_targets, cache)
97
+ end.flatten
98
+
99
+ # add the dendencies
100
+ dependency_targets = targets.map {|t| t.recursive_dependent_targets }.flatten.uniq || []
101
+ targets = (targets + dependency_targets).uniq
102
+ else
103
+ targets = self.pod_targets
104
+ end
105
+
106
+ targets = targets.reject {|pod_target| sandbox.local?(pod_target.pod_name) }
107
+
108
+
109
+
110
+ # build!
111
+ Pod::UI.puts "Prebuild frameworks (total #{targets.count})"
112
+ Pod::Prebuild.remove_build_dir(sandbox_path)
113
+ targets.each do |target|
114
+ next unless target.should_build?
115
+ output_path = sandbox.framework_folder_path_for_target_name(target.name)
116
+
117
+ output_path.mkpath unless output_path.exist?
118
+ Pod::Prebuild.build(sandbox_path, target, output_path, bitcode_enabled)
119
+
120
+ # save the resource paths for later installing
121
+ if target.static_framework? and !target.resource_paths.empty?
122
+ framework_path = output_path + target.framework_name
123
+ standard_sandbox_path = sandbox.standard_sanbox_path
124
+ path_objects = target.resource_paths.select{|f| f.start_with? "${PODS_ROOT}"}.map do |path|
125
+ object = Prebuild::Passer::ResourcePath.new
126
+ object.real_file_path = framework_path + File.basename(path)
127
+ object.target_file_path = path.gsub('${PODS_ROOT}', standard_sandbox_path.to_s)
128
+ object
129
+ end
130
+ Prebuild::Passer.resources_to_copy_for_static_framework[target.name] = path_objects
131
+ end
132
+
133
+ end
134
+ Pod::Prebuild.remove_build_dir(sandbox_path)
135
+
136
+
137
+ # copy vendored libraries and frameworks
138
+ targets.each do |target|
139
+ root_path = self.sandbox.pod_dir(target.name)
140
+ target_folder = sandbox.framework_folder_path_for_target_name(target.name)
141
+
142
+ # If target shouldn't build, we copy all the original files
143
+ # This is for target with only .a and .h files
144
+ if not target.should_build?
145
+ Prebuild::Passer.target_names_to_skip_integration_framework << target.name
146
+ FileUtils.cp_r(root_path, target_folder, :remove_destination => true)
147
+ next
148
+ end
149
+
150
+ target.spec_consumers.each do |consumer|
151
+ file_accessor = Sandbox::FileAccessor.new(root_path, consumer)
152
+ lib_paths = file_accessor.vendored_frameworks || []
153
+ lib_paths += file_accessor.vendored_libraries
154
+ # @TODO dSYM files
155
+ lib_paths.each do |lib_path|
156
+ relative = lib_path.relative_path_from(root_path)
157
+ destination = target_folder + relative
158
+ destination.dirname.mkpath unless destination.dirname.exist?
159
+ FileUtils.cp_r(lib_path, destination, :remove_destination => true)
160
+ end
161
+ end
162
+ end
163
+
164
+ # save the pod_name for prebuild framwork in sandbox
165
+ targets.each do |target|
166
+ sandbox.save_pod_name_for_target target
167
+ end
168
+
169
+ # Remove useless files
170
+ # remove useless pods
171
+ all_needed_names = self.pod_targets.map(&:name).uniq
172
+ useless_target_names = sandbox.exsited_framework_target_names.reject do |name|
173
+ all_needed_names.include? name
174
+ end
175
+ useless_target_names.each do |name|
176
+ path = sandbox.framework_folder_path_for_target_name(name)
177
+ path.rmtree if path.exist?
178
+ end
179
+
180
+ if not Podfile::DSL.dont_remove_source_code
181
+ # only keep manifest.lock and framework folder in _Prebuild
182
+ to_remain_files = ["Manifest.lock", File.basename(existed_framework_folder)]
183
+ to_delete_files = sandbox_path.children.select do |file|
184
+ filename = File.basename(file)
185
+ not to_remain_files.include?(filename)
186
+ end
187
+ to_delete_files.each do |path|
188
+ path.rmtree if path.exist?
189
+ end
190
+ else
191
+ # just remove the tmp files
192
+ path = sandbox.root + 'Manifest.lock.tmp'
193
+ path.rmtree if path.exist?
194
+ end
195
+
196
+
197
+
198
+ end
199
+
200
+
201
+ # patch the post install hook
202
+ old_method2 = instance_method(:run_plugins_post_install_hooks)
203
+ define_method(:run_plugins_post_install_hooks) do
204
+ old_method2.bind(self).()
205
+ if Pod::is_prebuild_stage
206
+ self.prebuild_frameworks!
207
+ end
208
+ end
209
+
210
+
211
+ end
212
+ end
@@ -0,0 +1,3 @@
1
+ module CocoapodsPrecompile
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,97 @@
1
+ require_relative '../tool/tool'
2
+ require_relative 'prebuild_sandbox'
3
+
4
+ module Pod
5
+
6
+ # a flag that indicate stages
7
+ class_attr_accessor :is_prebuild_stage
8
+
9
+
10
+ # a switch for the `pod` DSL to make it only valid for ':binary => true'
11
+ class Podfile
12
+ module DSL
13
+
14
+ @@enable_prebuild_patch = false
15
+
16
+ # when enable, `pod` function will skip all pods without 'prebuild => true'
17
+ def self.enable_prebuild_patch(value)
18
+ @@enable_prebuild_patch = value
19
+ end
20
+
21
+ # --- patch ---
22
+ old_method = instance_method(:pod)
23
+
24
+ define_method(:pod) do |name, *args|
25
+ if !@@enable_prebuild_patch
26
+ old_method.bind(self).(name, *args)
27
+ return
28
+ end
29
+
30
+ # patched content
31
+ should_prebuild = Pod::Podfile::DSL.prebuild_all
32
+ local = false
33
+
34
+ options = args.last
35
+ if options.is_a?(Hash) and options[Pod::Prebuild.keyword] != nil
36
+ should_prebuild = options[Pod::Prebuild.keyword]
37
+ local = (options[:path] != nil)
38
+ end
39
+
40
+ if should_prebuild and (not local)
41
+ old_method.bind(self).(name, *args)
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+
48
+ # a force disable option for integral
49
+ class Installer
50
+ def self.force_disable_integration(value)
51
+ @@force_disable_integration = value
52
+ end
53
+
54
+ old_method = instance_method(:integrate_user_project)
55
+ define_method(:integrate_user_project) do
56
+ if @@force_disable_integration
57
+ return
58
+ end
59
+ old_method.bind(self).()
60
+ end
61
+ end
62
+
63
+ # a option to disable install complete message
64
+ class Installer
65
+ def self.disable_install_complete_message(value)
66
+ @@disable_install_complete_message = value
67
+ end
68
+
69
+ old_method = instance_method(:print_post_install_message)
70
+ define_method(:print_post_install_message) do
71
+ if @@disable_install_complete_message
72
+ return
73
+ end
74
+ old_method.bind(self).()
75
+ end
76
+ end
77
+
78
+ # option to disable write lockfiles
79
+ class Config
80
+
81
+ @@force_disable_write_lockfile = false
82
+ def self.force_disable_write_lockfile(value)
83
+ @@force_disable_write_lockfile = value
84
+ end
85
+
86
+ old_method = instance_method(:lockfile_path)
87
+ define_method(:lockfile_path) do
88
+ if @@force_disable_write_lockfile
89
+ # As config is a singleton, sandbox_root refer to the standard sandbox.
90
+ return PrebuildSandbox.from_standard_sanbox_path(sandbox_root).root + 'Manifest.lock.tmp'
91
+ else
92
+ return old_method.bind(self).()
93
+ end
94
+ end
95
+ end
96
+
97
+ end
@@ -0,0 +1,78 @@
1
+ # ABOUT NAMES
2
+ #
3
+ # There are many kinds of name in cocoapods. Two main names are widely used in this plugin.
4
+ # - root_spec.name (spec.root_name, targe.pod_name):
5
+ # aka "pod_name"
6
+ # the name we use in podfile. the concept.
7
+ #
8
+ # - target.name:
9
+ # aka "target_name"
10
+ # the name of the final target in xcode project. the final real thing.
11
+ #
12
+ # One pod may have multiple targets in xcode project, due to one pod can be used in mutiple
13
+ # platform simultaneously. So one `root_spec.name` may have multiple coresponding `target.name`s.
14
+ # Therefore, map a spec to/from targets is a little complecated. It's one to many.
15
+ #
16
+
17
+ # Tool to transform Pod_name to target efficiently
18
+ module Pod
19
+ def self.fast_get_targets_for_pod_name(pod_name, targets, cache)
20
+ pod_name_to_targets_hash = nil
21
+ if cache.empty?
22
+ pod_name_to_targets_hash = targets.reduce({}) do |sum, target|
23
+ array = sum[target.pod_name] || []
24
+ array << target
25
+ sum[target.pod_name] = array
26
+ sum
27
+ end
28
+ cache << pod_name_to_targets_hash
29
+ else
30
+ pod_name_to_targets_hash = cache.first
31
+ end
32
+
33
+ pod_name_to_targets_hash[pod_name] || []
34
+ end
35
+ end
36
+
37
+
38
+
39
+
40
+
41
+
42
+ # Target:
43
+
44
+ # def pod_name
45
+ # root_spec.name
46
+ # end
47
+
48
+ # def name
49
+ # pod_name + #{scope_suffix}
50
+ # end
51
+
52
+ # def product_module_name
53
+ # root_spec.module_name
54
+ # end
55
+
56
+ # def framework_name
57
+ # "#{product_module_name}.framework"
58
+ # end
59
+
60
+ # def product_name
61
+ # if requires_frameworks?
62
+ # framework_name
63
+ # else
64
+ # static_library_name
65
+ # end
66
+ # end
67
+
68
+ # def product_basename
69
+ # if requires_frameworks?
70
+ # product_module_name
71
+ # else
72
+ # label
73
+ # end
74
+ # end
75
+
76
+ # def framework_name
77
+ # "#{product_module_name}.framework"
78
+ # end