cocoapods-precompile 0.1.0

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,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