cocoapods-jxedt 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,210 @@
1
+ module Jxedt
2
+ class Sandbox
3
+ attr_accessor :sandbox
4
+
5
+ def initialize(path=nil)
6
+ @sandbox_path = path
7
+ end
8
+
9
+ def self.from_sandbox(sandbox)
10
+ search_path = Jxedt.config.binary_dir
11
+ binary_dir = search_path.empty? ? nil : sandbox.root + search_path
12
+ check_sandbox = Sandbox.new(binary_dir)
13
+ check_sandbox.sandbox = sandbox
14
+ check_sandbox
15
+ end
16
+
17
+ def binary_dir
18
+ @binary_dir ||= Pathname.new(@sandbox_path)
19
+ end
20
+
21
+ def target_paths
22
+ return [] if @sandbox_path.nil?
23
+ return [] unless binary_dir.exist?
24
+ return [] if @sandbox.source_lockfile.nil?
25
+ @targets ||= binary_dir.children().map do |target_path|
26
+ if target_path.directory? && (not target_path.children.empty?)
27
+ hash_key = @sandbox.source_lockfile.spec_checksums_hash_key(target_path.basename.to_s)
28
+ target_path if !(hash_key.nil?) && (target_path + "#{hash_key}.checksum").exist?
29
+ end
30
+ end.reject(&:nil?).uniq
31
+ @targets
32
+ end
33
+
34
+ def existed_target_names(name)
35
+ target_paths.select { |pair| "#{pair.basename}" == "#{name}" }.map { |pair| pair.basename }
36
+ end
37
+
38
+ def framework_folder_path_for_target_name(name)
39
+ target_paths.select { |pair| pair.basename == name }.last
40
+ end
41
+
42
+ def prebuild_vendored_frameworks(name)
43
+ target_path = target_paths.select { |pair| "#{pair.basename}" == "#{name}" }.last
44
+ return [] if target_path.nil?
45
+
46
+ configuration_enable = target_path.children().select { |path| "#{path.basename}" == 'Debug' || "#{path.basename}" == 'Release' }.count == 2
47
+ if configuration_enable
48
+ xcconfig_configuration_alias = Jxedt.config.xcconfig_configuration_alias
49
+ ["#{xcconfig_configuration_alias}-Release/*.{framework,xcframework}"]
50
+ else
51
+ ["*.{framework,xcframework}"]
52
+ end
53
+ end
54
+
55
+ def prebuild_bundles(name)
56
+ target_path = target_paths.select { |pair| "#{pair.basename}" == "#{name}" }.last
57
+ return [] if target_path.nil?
58
+
59
+ configuration_enable = target_path.children().select { |path| "#{path.basename}" == 'Debug' || "#{path.basename}" == 'Release' }.count == 2
60
+ if configuration_enable
61
+ xcconfig_configuration_alias = Jxedt.config.xcconfig_configuration_alias
62
+ ["#{xcconfig_configuration_alias}-Release/*.bundle"]
63
+ else
64
+ ["*.bundle"]
65
+ end
66
+ end
67
+ end
68
+
69
+ class Prebuild
70
+ def initialize(source_installer)
71
+ @source_installer = source_installer
72
+ end
73
+
74
+ def targets_to_prebuild
75
+ explicit_prebuild_pod_names = @source_installer.aggregate_targets.flat_map { |target|
76
+ target.target_definition.explicit_prebuild_pod_names
77
+ }.uniq
78
+
79
+ reject_prebuild_pod_names = @source_installer.aggregate_targets.flat_map { |target|
80
+ target.target_definition.reject_prebuild_pod_names
81
+ }.uniq
82
+
83
+ targets = @source_installer.pod_targets.select { |target|
84
+ next unless target.should_build?
85
+ next unless target.name == target.pod_name
86
+ next if reject_prebuild_pod_names.include?(target.pod_name)
87
+ explicit_prebuild_pod_names.include?(target.pod_name) || Jxedt.config.all_binary_enabled?
88
+ }
89
+ targets.reject! { |target| @source_installer.sandbox.local?(target.pod_name) } unless Jxedt.config.dev_pods_enabled?
90
+ targets.reject! { |target| Jxedt.config.excluded_pods.include?(target.pod_name) }
91
+ targets
92
+ end
93
+
94
+ def pods_to_prebuild
95
+ targets_to_prebuild.map(&:name).to_a
96
+ end
97
+
98
+ def build
99
+ check_sandbox = Jxedt::Sandbox.from_sandbox(@source_installer.sandbox)
100
+ existed_target_names = check_sandbox.target_paths.map { |pair| pair.basename.to_s }
101
+ targets = targets_to_prebuild.reject { |target| existed_target_names.include?(target.name.to_s) }
102
+
103
+ Pod::UI.puts "Prebuild total count: #{targets.size}"
104
+ Pod::UI.puts "Prebuild targets: #{ targets.map(&:name)}"
105
+ return if targets.empty?
106
+
107
+ require_relative 'pod-room/xcodebuild_command'
108
+
109
+ clear_output_path
110
+ case targets[0].platform.name
111
+ when :ios, :tvos, :watchos
112
+ Jxedt.config.support_configurations.each do |configuration|
113
+ Pod::UI.puts "Prebuild configuration: #{configuration}"
114
+ options = make_options
115
+ options[:configuration] = configuration
116
+ options[:targets] = targets
117
+ options[:output_path] = output_path + configuration
118
+ Jxedt::XcodebuildCommand.new(options).run
119
+ end
120
+ when :osx
121
+ Jxedt.config.support_configurations.each do |configuration|
122
+ Pod::UI.puts "Prebuild configuration: #{configuration}"
123
+ options = make_options
124
+ xcodebuild(
125
+ sandbox: options[:sandbox],
126
+ targets: targets,
127
+ configuration: configuration,
128
+ sdk: "macosx",
129
+ args: options[:args]
130
+ )
131
+ end
132
+ else
133
+ raise "Unsupported platform for '#{targets[0].name}': '#{targets[0].platform.name}'"
134
+ end
135
+
136
+ make_prebuild(targets)
137
+ clear_output_path
138
+ end
139
+
140
+ def make_prebuild(targets)
141
+ lockfile = @source_installer.lockfile
142
+ checksums = lockfile.internal_data["SPEC CHECKSUMS"] || {}
143
+ checkout_options = lockfile.internal_data["CHECKOUT OPTIONS"] || {}
144
+
145
+ # 目标binary路径
146
+ binary_path = output_path.parent
147
+ prebuild_targets = targets.map(&:name).to_a
148
+ prebuild_targets.map {|target_name|
149
+ target_path = binary_path + target_name
150
+ target_path.rmtree if target_path.exist?
151
+ }
152
+
153
+ # make prebuild files
154
+ configurations = Jxedt.config.support_configurations
155
+ Jxedt.config.support_configurations.each do |configuration|
156
+ configuration_path = output_path + configuration
157
+ next unless configuration_path.exist?
158
+
159
+ configuration_path.children().each do |child|
160
+ if child.directory? and (not child.children.empty?)
161
+ name = child.basename.to_s
162
+ next unless prebuild_targets.include?(name)
163
+
164
+ target_path = binary_path + name
165
+ target_path += configuration if configurations.size > 1
166
+ target_path.mkpath unless target_path.exist?
167
+ command = "cp -r #{child}/ #{target_path}"
168
+ `#{command}`
169
+
170
+ # touch checksum
171
+ checksum = nil
172
+ checksum = checkout_options[name][:commit] unless checkout_options[name].nil? # commitid有值则使用commitid
173
+ checksum = checksums[name] if checksum.nil?
174
+ `echo #{command} "\n" >> #{binary_path}/#{name}/#{checksum}.checksum` unless checksum.nil?
175
+ end
176
+ end
177
+ end
178
+ end
179
+
180
+ def make_options
181
+ options = {}
182
+ options[:sandbox] = @source_installer.sandbox
183
+ options[:build_dir] = build_dir
184
+ options[:output_path] = output_path
185
+ options[:clean_build] = Jxedt.config.clean_build?
186
+ options[:bitcode_enabled] = Jxedt.config.bitcode_enabled?
187
+ options[:device_build_enabled] = Jxedt.config.device_build_enabled?
188
+ options[:simulator_build_enabled] = Jxedt.config.simulator_build_enabled?
189
+ options[:disable_dsym] = Jxedt.config.disable_dsym?
190
+ options[:log_path] = Jxedt.config.build_log_path
191
+ options[:args] = Jxedt.config.build_args
192
+ options
193
+ end
194
+
195
+ def build_dir
196
+ sandbox = @source_installer.sandbox
197
+ sandbox.root.parent + "build"
198
+ end
199
+
200
+ def output_path
201
+ sandbox = @source_installer.sandbox
202
+ sandbox.root + Jxedt.config.binary_dir + "GeneratedFrameworks"
203
+ end
204
+
205
+ def clear_output_path
206
+ path = output_path
207
+ path.rmtree if path.exist?
208
+ end
209
+ end
210
+ end
@@ -0,0 +1,103 @@
1
+ module Pod
2
+ class Target
3
+ # @since 1.5.0
4
+ class BuildSettings
5
+ # missing framework header search paths
6
+ def missing_framework_header_search_path(pt)
7
+ return [] unless pt.frame_header_search_paths_enable?
8
+
9
+ paths = []
10
+ pt.file_accessors.each do |file_accessor|
11
+ # xcframeworks
12
+ greater_than_or_equal_to_1_10_0 = Gem::Version.new(Pod::VERSION) >= Gem::Version.new('1.10.0')
13
+ greater_than_or_equal_to_1_11_0 = Gem::Version.new(Pod::VERSION) >= Gem::Version.new('1.11.0')
14
+ file_accessor.vendored_xcframeworks.map { |path|
15
+ if greater_than_or_equal_to_1_11_0
16
+ Xcode::XCFramework.new(file_accessor.spec.name, path)
17
+ else
18
+ Xcode::XCFramework.new(path)
19
+ end
20
+ }.each { |xcfwk|
21
+ xcfwk.slices.each { |slice|
22
+ fwk_name = slice.path.basename
23
+ if greater_than_or_equal_to_1_11_0
24
+ paths.push "${PODS_XCFRAMEWORKS_BUILD_DIR}/#{xcfwk.target_name}/#{fwk_name}/Headers"
25
+ elsif greater_than_or_equal_to_1_10_0
26
+ paths.push "${PODS_XCFRAMEWORKS_BUILD_DIR}/#{fwk_name.to_s.gsub(/\.framework$/, '')}/#{fwk_name}/Headers"
27
+ else
28
+ paths.push "${PODS_CONFIGURATION_BUILD_DIR}/#{fwk_name}/Headers"
29
+ end
30
+ }
31
+ }
32
+ # Cocoapods 1.9.x bugs
33
+ if Gem::Version.new(Pod::VERSION) < Gem::Version.new('1.10.0')
34
+ file_accessor.vendored_xcframeworks.each { |path|
35
+ Dir.glob("#{path.to_s}/**/*.framework").each do |fwk_path|
36
+ header_path = Pathname.new("#{fwk_path}/Headers")
37
+ next unless header_path.exist?
38
+ paths.push "${PODS_ROOT}/#{header_path.relative_path_from(pt.sandbox.root)}"
39
+ end
40
+ }
41
+ end
42
+
43
+ # frameworks
44
+ (file_accessor.vendored_frameworks - file_accessor.vendored_xcframeworks).each { |framework|
45
+ header_path = Pathname.new("#{framework}/Headers")
46
+ next unless header_path.exist?
47
+ paths.push "${PODS_ROOT}/#{header_path.relative_path_from(pt.sandbox.root)}"
48
+ }
49
+ end
50
+ replace_xcconfig_configuration_paths(paths)
51
+ paths.uniq
52
+ end
53
+
54
+ # replace different configuration xcconfig
55
+ def replace_xcconfig_configuration_paths(paths)
56
+ xcconfig_configuration_alias = Jxedt.config.xcconfig_configuration_alias
57
+ support_configurations = Jxedt.config.support_configurations
58
+ match_configuration = support_configurations.join('|')
59
+ paths.map! { |path|
60
+ if path =~ /#{xcconfig_configuration_alias}-(#{match_configuration})/
61
+ configuration = @configuration.to_s.downcase
62
+ matchs = support_configurations.select {|name| name.downcase == configuration }
63
+ path.gsub!(/#{xcconfig_configuration_alias}-(#{match_configuration})/, "#{xcconfig_configuration_alias}-#{matchs.first}") if matchs.count == 1
64
+ end
65
+ path
66
+ }
67
+ paths
68
+ end
69
+
70
+ # A subclass that generates build settings for a `PodTarget`
71
+ class AggregateTargetSettings
72
+ # @return [Array<String>]
73
+ alias_method :old_raw_header_search_paths, :_raw_header_search_paths
74
+ def _raw_header_search_paths
75
+ header_search_paths = old_raw_header_search_paths
76
+ header_search_paths.concat pod_targets.flat_map { |pt| missing_framework_header_search_path(pt) }
77
+ header_search_paths.uniq
78
+ end
79
+ end
80
+
81
+ # A subclass that generates build settings for a {PodTarget}
82
+ class PodTargetSettings
83
+ # @return [Array<String>]
84
+ alias_method :old_raw_header_search_paths, :_raw_header_search_paths
85
+ def _raw_header_search_paths
86
+ header_search_paths = old_raw_header_search_paths
87
+ header_search_paths.concat dependent_targets.flat_map { |pt| missing_framework_header_search_path(pt) } if target.should_build?
88
+ header_search_paths.uniq
89
+ end
90
+
91
+ # 按照规则替换framework_search_paths,兼容不同的configuration
92
+ # 从编译上来说,仅仅替换了framework_search_paths的路径就够了
93
+ # @return [Array<String>]
94
+ alias_method :old_raw_framework_search_paths, :_raw_framework_search_paths
95
+ def _raw_framework_search_paths
96
+ framework_search_paths = old_raw_framework_search_paths
97
+ replace_xcconfig_configuration_paths(framework_search_paths)
98
+ framework_search_paths
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,157 @@
1
+ module Pod
2
+ class Command
3
+ class JxedtCommand < Command
4
+ class Header < JxedtCommand
5
+ self.summary = 'header fix'
6
+ self.description = <<-DESC
7
+ 修改头文件引用问题。\n
8
+ 例如修改#import "AFNetworking.h"或#import <AFNetworking.h>这种头文件引用方式为#import <AFNetworking/AFNetworking.h>\n
9
+ 使用方式:\n
10
+ 到Podfile文件所在目录执行以下命令\n
11
+ 1. 修改某个组件的头文件引用\n
12
+ pod jxedt headerfix --name=PodA --dir=PodA RealPath --write\n
13
+ 2. 修改工程的头文件引用\n
14
+ pod jxedt headerfix --dir=project path --write\n
15
+ DESC
16
+ self.command = 'headerfix'
17
+ self.arguments = [
18
+ ]
19
+ def self.options
20
+ [
21
+ ['--name', '需要修改header引用的pod name。没有该参数则会认为修改的是工程中的文件'],
22
+ ['--dir', '需要修改的文件夹路径,一般情况下为pod组件的真实目录。如果修改的pod组件是development pods,也可以不传该参数。'],
23
+ ['--write', '修改命中的头文件引用,不写入则直接输出需要修改的文件和修改内容。默认false'],
24
+ ['--suffix', '处理的文件后缀,默认处理\'h,m,mm,pch\'后缀的文件'],
25
+ ['--header-regulation', 'header name的正则,默认为\'[\w+-]*\.h\',如果不满足也可以自定义'],
26
+ ]
27
+ end
28
+ def initialize(argv)
29
+ @pod_name = argv.option('name')
30
+ @dir = argv.option('dir')
31
+ @suffix = argv.option('suffix', 'h,m,mm,pch')
32
+ @force_write = argv.flag?('write', false)
33
+ @header_regulation = argv.option('header-regulation')
34
+ super
35
+ end
36
+
37
+ def validate!
38
+ super
39
+ help! 'A podspec name or dir is required.' if @pod_name.nil? && @dir.nil?
40
+ end
41
+
42
+ def run
43
+ @installer = installer_for_config
44
+ help! '请检查命令执行路径,需要在Podfile文件所在目录执行' if @installer.nil?
45
+
46
+ @installer.sandbox.prepare # sandbox prepare
47
+ @installer.resolve_dependencies # 解析依赖
48
+ # @installer.integrate # 不需要执行也可以解析依赖关系
49
+
50
+ process_target_files = process_target_files!
51
+ dependent_targets = dependent_targets!
52
+
53
+ # 查找
54
+ public_header_mapping = {}
55
+ dependent_targets.each {|target|
56
+ next unless target.should_build?
57
+
58
+ # 获取所有.h文件
59
+ all_header_files = target.all_files.select {|file| file.to_s =~ /#{header_name_regulation}$/ }
60
+ # 建立header文件和product_module_name的映射
61
+ public_header_mapping.merge! all_header_files.reduce({}) { |hash, file|
62
+ basename = File.basename(file)
63
+ hash.update(basename.to_s => target.product_module_name)
64
+ }
65
+ }
66
+
67
+ # 遍历需要处理的文件
68
+ record = []
69
+ process_target_files.each {|file_path|
70
+ changed = false
71
+ lines = File.readlines(file_path)
72
+ # 获取命中的行
73
+ File.foreach(file_path).with_index {|line, num|
74
+ matched = line =~ /^\s*#import\s*"#{header_name_regulation}"\s*\n$/ || line =~ /^\s*#import\s*<#{header_name_regulation}>\s*\n$/
75
+ next unless matched
76
+
77
+ header_name = line.match(/(?<=")#{header_name_regulation}(?=")/) || line.match(/(?<=<)#{header_name_regulation}(?=>)/)
78
+ next unless public_header_mapping.include?("#{header_name}")
79
+
80
+ project_module_name = public_header_mapping["#{header_name}"]
81
+ replace_line = "#import " << "<#{project_module_name}/#{header_name}>\n"
82
+ lines[num] = replace_line
83
+ changed = true
84
+ record << "#{file_path} 第#{num}行,#{line} => #{replace_line}"
85
+ }
86
+ File.open(file_path, 'w') { |f| f.write(lines.join) } if changed && @force_write
87
+ }
88
+ puts "需要修改的地方共有:#{record.size} 处"
89
+ puts JSON.pretty_generate(record) if record.size > 0
90
+ end
91
+
92
+ def installer_for_config
93
+ config = Pod::Config.instance
94
+ return if config.podfile.nil?
95
+ Pod::Installer.new(config.sandbox, config.podfile, config.lockfile)
96
+ end
97
+
98
+ def header_name_regulation
99
+ @regulation = @header_regulation || '[\w+-]*\.h' # header name的规则 [a-zA-Z0-9_+-]
100
+ @regulation
101
+ end
102
+
103
+ def process_target_files!
104
+ process_target_files = []
105
+ unless @dir.nil?
106
+ def walk(path, &action)
107
+ return unless path.exist?
108
+ path.children.each do |child|
109
+ result = action.call(child, &action)
110
+ walk(child, &action) if result and child.directory?
111
+ end
112
+ end
113
+
114
+ path = Pathname.new(@dir)
115
+ walk(path) do |child|
116
+ if child.directory? and [".framework", ".xcframework", ".bundle", ".dSYM"].include? child.extname
117
+ next false
118
+ elsif child.file?
119
+ suffix = @suffix.split(',').join('|')
120
+ process_target_files << (path + child) if child.to_s =~ /.*\.(#{suffix})$/
121
+ next true
122
+ else
123
+ next true
124
+ end
125
+ end
126
+ else
127
+ process_target_files = @installer.pod_targets.flat_map {|target|
128
+ suffix = @suffix.split(',').join('|')
129
+ target.all_files.select {|file| file.to_s =~ /.*\.(#{suffix})$/ } if target.pod_name.to_s == @pod_name
130
+ }.reject(&:nil?).uniq
131
+ end
132
+ process_target_files
133
+ end
134
+
135
+ def dependent_targets!
136
+ dependent_targets = @installer.pod_targets
137
+ unless @pod_name.nil?
138
+ # 递归查找依赖
139
+ def recursion_dependent_targets(target)
140
+ target.dependent_targets.flat_map {|t|
141
+ targets = [t]
142
+ targets += recursion_dependent_targets(t) if target.dependent_targets.size > 0
143
+ targets
144
+ }.reject(&:nil?)
145
+ end
146
+
147
+ # 获取依赖
148
+ dependent_targets = @installer.pod_targets.flat_map {|target|
149
+ recursion_dependent_targets(target) if target.pod_name.to_s == @pod_name
150
+ }.reject(&:nil?).uniq
151
+ end
152
+ dependent_targets
153
+ end
154
+ end
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,40 @@
1
+ require_relative 'options/options'
2
+ require_relative 'header/header'
3
+
4
+ module Pod
5
+ class Command
6
+ class JxedtCommand < Command
7
+ self.summary = 'cocoapods-jxedt插件命令工具。'
8
+
9
+ self.description = <<-DESC
10
+ cocoapods-jxedt插件命令工具。
11
+ DESC
12
+
13
+ self.command = 'jxedt'
14
+ self.abstract_command = true
15
+
16
+ def self.options
17
+ [
18
+ ['--version', 'Show cocoapods-jxedt version'],
19
+ ].concat(super)
20
+ end
21
+
22
+ def initialize(argv)
23
+ @version = argv.flag?('version', false)
24
+ super
25
+ end
26
+
27
+ def validate!
28
+ if @version
29
+ require 'cocoapods-jxedt/gem_version'
30
+ puts "#{CocoapodsJxedt::VERSION}"
31
+ return
32
+ end
33
+ super
34
+ end
35
+
36
+ def run
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,33 @@
1
+ module Pod
2
+ class Command
3
+ class JxedtCommand < Command
4
+ class Options < JxedtCommand
5
+ self.summary = 'binary配置参数介绍'
6
+ self.description = <<-DESC
7
+ binary插件配置介绍
8
+ DESC
9
+ self.command = 'options'
10
+ self.arguments = [
11
+ ]
12
+ def self.options
13
+ []
14
+ end
15
+ def initialize(argv)
16
+ super
17
+ end
18
+
19
+ def validate!
20
+ super
21
+ end
22
+
23
+ def run
24
+ require 'cocoapods-jxedt/binary/config'
25
+ require 'json'
26
+
27
+ dsl_config = Jxedt::Config::APPLICABLE_DSL_CONFIG
28
+ puts JSON.pretty_generate(dsl_config)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1 @@
1
+ require 'cocoapods-jxedt/command/jxedt'
@@ -0,0 +1,3 @@
1
+ module CocoapodsJxedt
2
+ VERSION = "0.0.9"
3
+ end
@@ -0,0 +1,12 @@
1
+ class Module
2
+ def class_alias_method(to, from)
3
+ # https://tieba.baidu.com/p/5535445605?red_tag=0735709674 贴吧大神给出的方案
4
+ # 类方法可以看做singleton class(单例类)的实例方法,下面两个方法都可以,上面这个方式也适用于早期的ruby版本
5
+ (class << self;self;end).send(:alias_method, to, from)
6
+ # self.singleton_class.send(:alias_method, to, from)
7
+ end
8
+
9
+ def class_attr_accessor(symbol)
10
+ self.class.send(:attr_accessor, symbol)
11
+ end
12
+ end
@@ -0,0 +1 @@
1
+ require 'cocoapods-jxedt/gem_version'
@@ -0,0 +1,3 @@
1
+ require 'cocoapods-jxedt/command'
2
+ require 'cocoapods-jxedt/binary/main.rb'
3
+ require 'cocoapods-jxedt/tool'