cocoapods-xlbuild 1.0.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,239 @@
1
+ require_relative 'rome/build_framework'
2
+ require_relative 'helper/passer'
3
+ require_relative 'helper/target_checker'
4
+
5
+
6
+ # patch prebuild ability
7
+ module Pod
8
+ class Installer
9
+
10
+
11
+ private
12
+
13
+ def local_manifest
14
+ if not @local_manifest_inited
15
+ @local_manifest_inited = true
16
+ raise "This method should be call before generate project" unless self.analysis_result == nil
17
+ @local_manifest = self.sandbox.manifest
18
+ end
19
+ @local_manifest
20
+ end
21
+
22
+ # @return [Analyzer::SpecsState]
23
+ def prebuild_pods_changes
24
+ return nil if local_manifest.nil?
25
+ if @prebuild_pods_changes.nil?
26
+ changes = local_manifest.detect_changes_with_podfile(podfile)
27
+ @prebuild_pods_changes = Analyzer::SpecsState.new(changes)
28
+ # save the chagnes info for later stage
29
+ Pod::Prebuild::Passer.prebuild_pods_changes = @prebuild_pods_changes
30
+ end
31
+ @prebuild_pods_changes
32
+ end
33
+
34
+
35
+ public
36
+
37
+ # check if need to prebuild
38
+ def have_exact_prebuild_cache?
39
+ # check if need build frameworks
40
+ return false if local_manifest == nil
41
+
42
+ changes = prebuild_pods_changes
43
+ added = changes.added
44
+ changed = changes.changed
45
+ unchanged = changes.unchanged
46
+ deleted = changes.deleted
47
+
48
+ exsited_framework_pod_names = sandbox.exsited_framework_pod_names
49
+ missing = unchanged.select do |pod_name|
50
+ not exsited_framework_pod_names.include?(pod_name)
51
+ end
52
+
53
+ needed = (added + changed + deleted + missing)
54
+ return needed.empty?
55
+ end
56
+
57
+
58
+ # The install method when have completed cache
59
+ def install_when_cache_hit!
60
+ # just print log
61
+ self.sandbox.exsited_framework_target_names.each do |name|
62
+ UI.puts "Using #{name}"
63
+ end
64
+ end
65
+
66
+ # Build the needed framework files
67
+ def prebuild_frameworks!
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
+ use_static_framework = Pod::Podfile::DSL.static_binary
73
+ targets = []
74
+
75
+ if local_manifest != nil
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
+ root_names_to_update = (added + changed + missing).uniq
90
+ # 生成预编译target
91
+ cache = []
92
+ targets = root_names_to_update.map do |pod_name|
93
+ tars = Pod.fast_get_targets_for_pod_name(pod_name, self.pod_targets, cache)
94
+ if tars.nil?
95
+ tars = []
96
+ end
97
+ tars
98
+ end.flatten
99
+
100
+ # 添加依赖
101
+ dependency_targets = targets.map {|t| t.recursive_dependent_targets }.flatten.uniq || []
102
+ dependency_targets = dependency_targets.select do |tar|
103
+ sandbox.existed_target_version_for_pod_name(tar.pod_name) != tar.version
104
+ end
105
+ targets = (targets + dependency_targets).uniq
106
+ else
107
+ targets = self.pod_targets
108
+ end
109
+
110
+ targets = targets.reject {|pod_target| sandbox.local?(pod_target.pod_name) }
111
+
112
+
113
+ # build!
114
+ Pod::UI.puts "Prebuild frameworks (total #{targets.count})"
115
+ Pod::Prebuild.remove_build_dir(sandbox_path)
116
+ targets.each do |target|
117
+ #linpeng edit + target.version
118
+ output_path = sandbox.framework_folder_path_for_target_name(target.name)
119
+ output_path.rmtree if output_path.exist?
120
+ if !target.should_build?
121
+ UI.puts "Prebuilding #{target.label}"
122
+ next
123
+ end
124
+ output_path.mkpath unless output_path.exist?
125
+ Pod::Prebuild.build(sandbox_path, target, output_path, bitcode_enabled, Podfile::DSL.custom_build_options, Podfile::DSL.custom_build_options_simulator)
126
+
127
+ # save the resource paths for later installing,动态库需要将frameworkwork中资源链接到pod上
128
+ if target.static_framework? and !target.resource_paths.empty?
129
+ framework_path = output_path + target.framework_name
130
+ standard_sandbox_path = sandbox.standard_sanbox_path
131
+
132
+ resources = begin
133
+ if Pod::VERSION.start_with? "1.5"
134
+ target.resource_paths
135
+ else
136
+ # resource_paths is Hash{String=>Array<String>} on 1.6 and above
137
+ # (use AFNetworking to generate a demo data)
138
+ # https://github.com/leavez/cocoapods-binary/issues/50
139
+ target.resource_paths.values.flatten
140
+ end
141
+ end
142
+ raise "Wrong type: #{resources}" unless resources.kind_of? Array
143
+ path_objects = resources.map do |path|
144
+ object = Prebuild::Passer::ResourcePath.new
145
+ object.real_file_path = framework_path + File.basename(path)
146
+ # 静态库资源目录处理
147
+ if use_static_framework
148
+ object.real_file_path = path.gsub('${PODS_ROOT}', existed_framework_folder.to_s) if path.start_with? '${PODS_ROOT}'
149
+ object.real_file_path = path.gsub("${PODS_CONFIGURATION_BUILD_DIR}", existed_framework_folder.to_s) if path.start_with? "${PODS_CONFIGURATION_BUILD_DIR}"
150
+ real_bundle_path = path.gsub('${PODS_ROOT}', sandbox_path.to_s) if path.start_with? '${PODS_ROOT}'
151
+ real_bundle_path = path.gsub('${PODS_CONFIGURATION_BUILD_DIR}', sandbox_path.to_s) if path.start_with? '${PODS_CONFIGURATION_BUILD_DIR}'
152
+ real_origin_path = Pathname.new(real_bundle_path)
153
+ real_file_path_obj = Pathname.new(object.real_file_path)
154
+ if real_origin_path.exist?
155
+ real_file_path_obj.parent.mkpath unless real_file_path_obj.parent.exist?
156
+ FileUtils.cp_r(real_origin_path, real_file_path_obj, :remove_destination => true)
157
+ end
158
+ end
159
+ object.target_file_path = path.gsub('${PODS_ROOT}', standard_sandbox_path.to_s) if path.start_with? '${PODS_ROOT}'
160
+ object.target_file_path = path.gsub("${PODS_CONFIGURATION_BUILD_DIR}", standard_sandbox_path.to_s) if path.start_with? "${PODS_CONFIGURATION_BUILD_DIR}"
161
+ object
162
+ end
163
+ Prebuild::Passer.resources_to_copy_for_static_framework[target.name] = path_objects
164
+ end
165
+ end
166
+ Pod::Prebuild.remove_build_dir(sandbox_path)
167
+
168
+ # copy vendored libraries and frameworks
169
+ targets.each do |target|
170
+ root_path = self.sandbox.pod_dir(target.name)
171
+ target_folder = sandbox.framework_folder_path_for_target_name(target.name)
172
+
173
+ # If target shouldn't build, we copy all the original files
174
+ # This is for target with only .a and .h files
175
+ if not target.should_build?
176
+ Prebuild::Passer.target_names_to_skip_integration_framework << target.name
177
+ FileUtils.cp_r(root_path, target_folder, :remove_destination => true)
178
+ next
179
+ end
180
+
181
+ target.spec_consumers.each do |consumer|
182
+ file_accessor = Sandbox::FileAccessor.new(root_path, consumer)
183
+ lib_paths = file_accessor.vendored_frameworks || []
184
+ lib_paths += file_accessor.vendored_libraries
185
+ # @TODO dSYM files
186
+ lib_paths.each do |lib_path|
187
+ relative = lib_path.relative_path_from(root_path)
188
+ destination = target_folder + relative
189
+ destination.dirname.mkpath unless destination.dirname.exist?
190
+ FileUtils.cp_r(lib_path, destination, :remove_destination => true)
191
+ end
192
+ end
193
+ end
194
+
195
+ # save the pod_name for prebuild framwork in sandbox
196
+ targets.each do |target|
197
+ sandbox.save_pod_name_for_target target
198
+ end
199
+
200
+ # Remove useless files
201
+ # remove useless pods
202
+ all_needed_names = self.pod_targets.map(&:name).uniq
203
+ useless_target_names = sandbox.exsited_framework_target_names.reject do |name|
204
+ all_needed_names.include? name
205
+ end
206
+ useless_target_names.each do |name|
207
+ path = sandbox.framework_folder_path_for_target_name(name)
208
+ path.rmtree if path.exist?
209
+ end
210
+
211
+ if Podfile::DSL.dont_remove_source_code
212
+ # just remove the tmp files
213
+ path = sandbox.root + 'Manifest.lock.tmp'
214
+ path.rmtree if path.exist?
215
+ else
216
+ # only keep manifest.lock and framework folder in _Prebuild
217
+ to_remain_files = ["Manifest.lock", File.basename(existed_framework_folder)]
218
+ to_delete_files = sandbox_path.children.select do |file|
219
+ filename = File.basename(file)
220
+ not to_remain_files.include?(filename)
221
+ end
222
+ to_delete_files.each do |path|
223
+ path.rmtree if path.exist?
224
+ end
225
+ end
226
+ end
227
+
228
+ # hook run_plugins_post_install_hooks 方法
229
+ install_hooks_method = instance_method(:run_plugins_post_install_hooks)
230
+ define_method(:run_plugins_post_install_hooks) do
231
+ puts "[HY].run_plugins_post_install_hooks 触发 state:#{Pod::is_prebuild_stage}"
232
+ install_hooks_method.bind(self).()
233
+ if Pod::is_prebuild_stage
234
+ #开始编译
235
+ self.prebuild_frameworks!
236
+ end
237
+ end
238
+ end
239
+ end
@@ -0,0 +1,55 @@
1
+
2
+ require 'xcodeproj'
3
+ require_relative '../helper/passer'
4
+ require_relative '../helper/prebuild_sandbox'
5
+
6
+ module Pod
7
+ class Installer
8
+ class PostInstallHooksContext
9
+ # 将源码引入主工程,方便源码调试
10
+ def refrence_source_code
11
+ sandbox_path = Pathname.new(sandbox.root)
12
+ pre_sandbox = Pod::PrebuildSandbox.from_standard_sandbox(sandbox)
13
+
14
+ exsited_framework_pod_names = pre_sandbox.exsited_framework_pod_names || []
15
+ proj_path = sandbox_path + get_project_name("Pods")
16
+
17
+ proj_path_new = Pathname.new(sandbox.project_path)
18
+
19
+ puts "[HY].沙盒路径:#{sandbox_path}"
20
+ project = Xcodeproj::Project.open(proj_path)
21
+ exsited_framework_pod_names.each do |target_name|
22
+ real_reference("_Prebuild/#{target_name}", project, target_name)
23
+ end
24
+ project.save;
25
+ end
26
+
27
+ private
28
+ def get_project_name(tageter_name)
29
+ return "#{tageter_name}.xcodeproj"
30
+ end
31
+
32
+ def real_reference(file_path, project, target_name)
33
+ group = project.main_group.find_subpath(File.join("SourceCode", target_name), true)
34
+ group.set_source_tree('SOURCE_ROOT')
35
+ group.set_path(file_path)
36
+ add_files_to_group(group)
37
+ end
38
+
39
+ #添加文件链接
40
+ def add_files_to_group(group)
41
+ Dir.foreach(group.real_path) do |entry|
42
+ filePath = File.join(group.real_path, entry)
43
+ # 过滤目录和.DS_Store文件
44
+ if entry != ".DS_Store" && !filePath.to_s.end_with?(".meta") &&entry != "." &&entry != ".." then
45
+ # 向group中增加文件引用
46
+ group.new_reference(filePath)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+
55
+
@@ -0,0 +1,44 @@
1
+ module Pod
2
+ class Command
3
+ # This is an example of a cocoapods plugin adding a top-level subcommand
4
+ # to the 'pod' command.
5
+ #
6
+ # You can also create subcommands of existing or new commands. Say you
7
+ # wanted to add a subcommand to `list` to show newly deprecated pods,
8
+ # (e.g. `pod list deprecated`), there are a few things that would need
9
+ # to change.
10
+ #
11
+ # - move this file to `lib/pod/command/list/deprecated.rb` and update
12
+ # the class to exist in the the Pod::Command::List namespace
13
+ # - change this class to extend from `List` instead of `Command`. This
14
+ # tells the plugin system that it is a subcommand of `list`.
15
+ # - edit `lib/cocoapods_plugins.rb` to require this file
16
+ #
17
+ # @todo Create a PR to add your plugin to CocoaPods/cocoapods.org
18
+ # in the `plugins.json` file, once your plugin is released.
19
+ #
20
+ class XLbuild < Command
21
+ self.summary = 'Short description of cocoapods-xlbuild.'
22
+
23
+ self.description = <<-DESC
24
+ Longer description of cocoapods-xlbuild.
25
+ DESC
26
+
27
+ # self.arguments = 'NAME'
28
+
29
+ def initialize(argv)
30
+ @name = argv.shift_argument
31
+ super
32
+ end
33
+
34
+ def validate!
35
+ super
36
+ help! 'A Pod name is required.' unless @name
37
+ end
38
+
39
+ def run
40
+ UI.puts "Add your implementation for the cocoapods-xlbuild plugin in #{__FILE__}"
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1 @@
1
+ require 'cocoapods-xlbuild/command/xlbuild'
@@ -0,0 +1,3 @@
1
+ module CocoapodsXLbuild
2
+ VERSION = "1.0.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 ':xlbuild => 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
@@ -0,0 +1,45 @@
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
+ class_attr_accessor :prebuild_pod_targets_changes
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
+ # 编译过的framework pod 名称
40
+ class_attr_accessor :static_build_pod_names
41
+ self.static_build_pod_names = []
42
+
43
+ end
44
+ end
45
+ end