cocoapods-privacy 0.5.2 → 0.6.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.
- checksums.yaml +4 -4
- data/README.md +7 -1
- data/lib/cocoapods-privacy/command/confuse/spec.rb +34 -0
- data/lib/cocoapods-privacy/command/install.rb +38 -5
- data/lib/cocoapods-privacy/command/privacy/config.rb +2 -2
- data/lib/cocoapods-privacy/command.rb +17 -2
- data/lib/cocoapods-privacy/common/BBSpec.rb +234 -0
- data/lib/cocoapods-privacy/common/BBSpecManager.rb +166 -0
- data/lib/cocoapods-privacy/common/config.rb +69 -0
- data/lib/cocoapods-privacy/confuse/ConfuseHunter.rb +506 -0
- data/lib/cocoapods-privacy/confuse/ConfuseModule.rb +150 -0
- data/lib/cocoapods-privacy/confuse/ConfuseUtils.rb +107 -0
- data/lib/cocoapods-privacy/confuse/ObjCMethodAPIConverter.rb +194 -0
- data/lib/cocoapods-privacy/confuse/SwiftCallAssembly.rb +24 -0
- data/lib/cocoapods-privacy/confuse/confuse_installer_hook.rb +290 -0
- data/lib/cocoapods-privacy/confuse/confuse_specification_hook.rb +56 -0
- data/lib/cocoapods-privacy/gem_version.rb +1 -1
- data/lib/cocoapods-privacy/privacy/PrivacyHunter.rb +12 -8
- data/lib/cocoapods-privacy/privacy/PrivacyModule.rb +2 -338
- data/lib/cocoapods-privacy/privacy/PrivacyUtils.rb +5 -13
- data/lib/cocoapods-privacy/privacy/privacy_installer_hook.rb +0 -1
- data/lib/cocoapods-privacy/privacy/privacy_specification_hook.rb +4 -1
- metadata +14 -4
- data/lib/cocoapods-privacy/privacy/PrivacyConfig.rb +0 -28
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ba881a65811e8640597663d499127914a78678976913fcb8352e873a1760dbda
|
4
|
+
data.tar.gz: 4fb771e904d423d13f4a188451ace0b4adca4f0683d3d0ce2230c56aa2948fda
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b714abed735826938d267bb5c8a16e28a01ae9a470cebb4725627adc6aeb8ad3b0b078b858cff7c16e3e33c0545e7d2303bb8a6855614bc7c6aacfcfc7cc457d
|
7
|
+
data.tar.gz: d1fc4f2e8ea3846969a6854cab16bf5eaf7468bbb085ab7e2ddcb566b6ac1eb4f320fbc42de60aad392804a9131b6183f5075ad1f35ec6f4acdbf47557a46060
|
data/README.md
CHANGED
@@ -103,7 +103,13 @@ $ pod privacy install
|
|
103
103
|
```
|
104
104
|
<img width="298" alt="截屏2024-02-02 10 59 59" src="https://github.com/ymoyao/cocoapods-privacy/assets/13619221/c6f10e36-0f62-497a-93d4-f8b336dc8df4">
|
105
105
|
|
106
|
-
After command, a PrivacyInfo.xcprivacy will create to you project Resources if empty.
|
106
|
+
After command, a PrivacyInfo.xcprivacy will create to you project Resources if empty.
|
107
|
+
|
108
|
+
Components that meet all of the following items will be processed.
|
109
|
+
* do not have their own privacy manifest file components
|
110
|
+
* in white list and not in black list components
|
111
|
+
* source code components(binary components please deal with command `pod privacy spec` )
|
112
|
+
|
107
113
|
|
108
114
|
## Notice
|
109
115
|
The plugin is focus on NSPrivacyAccessedAPITypes and automatically search and create workflow.
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Pod
|
2
|
+
class Command
|
3
|
+
class Confuse < Command
|
4
|
+
class Spec < Confuse
|
5
|
+
self.summary = '根据 podspec 创建对应混淆文件'
|
6
|
+
|
7
|
+
self.description = <<-DESC
|
8
|
+
根据podspec 创建对应混淆文件,并自动修改podspec文件。
|
9
|
+
DESC
|
10
|
+
|
11
|
+
self.arguments = [
|
12
|
+
CLAide::Argument.new('podspec_file', false, true),
|
13
|
+
]
|
14
|
+
|
15
|
+
def initialize(argv)
|
16
|
+
@podspec_file = argv.arguments!.first
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
def validate!
|
21
|
+
@podspec_file = @podspec_file ? @podspec_file : PrivacyUtils.podspec_file_path
|
22
|
+
unless @podspec_file && !@podspec_file.empty?
|
23
|
+
raise Informative, 'no podspec file were found, please run pod confuse podspec_file_path'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def run
|
28
|
+
ConfuseModule.load_module(@podspec_file)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'cocoapods-privacy/command'
|
2
|
-
|
2
|
+
#### 以下是隐私协议部分 ####
|
3
3
|
module Pod
|
4
4
|
class Config
|
5
5
|
attr_accessor :privacy_folds
|
@@ -18,8 +18,8 @@ module Pod
|
|
18
18
|
[
|
19
19
|
['--privacy', '使用该参数,会自动生成并更新PrivacyInfo.xcprivacy'],
|
20
20
|
['--privacy-folds=folds', '指定文件夹检索,多个文件夹使用逗号","分割'],
|
21
|
-
['--query', '仅查询隐私api,不做写入'],
|
22
|
-
['--all', '忽略黑名单和白名单限制,查询工程所有组件'],
|
21
|
+
['--privacy-query', '仅查询隐私api,不做写入'],
|
22
|
+
['--privacy-all', '忽略黑名单和白名单限制,查询工程所有组件'],
|
23
23
|
].concat(origin_options)
|
24
24
|
end
|
25
25
|
end
|
@@ -27,9 +27,9 @@ module Pod
|
|
27
27
|
alias_method :privacy_origin_initialize, :initialize
|
28
28
|
def initialize(argv)
|
29
29
|
privacy_folds = argv.option('privacy-folds', '').split(',')
|
30
|
+
is_query = argv.flag?('privacy-query',false)
|
31
|
+
is_all = argv.flag?('privacy-all',false)
|
30
32
|
is_privacy = argv.flag?('privacy',false)
|
31
|
-
is_query = argv.flag?('query',false)
|
32
|
-
is_all = argv.flag?('all',false)
|
33
33
|
privacy_origin_initialize(argv)
|
34
34
|
instance = Pod::Config.instance
|
35
35
|
instance.privacy_folds = privacy_folds
|
@@ -39,4 +39,37 @@ module Pod
|
|
39
39
|
end
|
40
40
|
end
|
41
41
|
end
|
42
|
+
end
|
43
|
+
|
44
|
+
#### 以下是混淆部分 ####
|
45
|
+
module Pod
|
46
|
+
class Config
|
47
|
+
attr_accessor :confuse_pattern
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
module Pod
|
52
|
+
class Command
|
53
|
+
class Install < Command
|
54
|
+
class << self
|
55
|
+
alias_method :confuse_origin_options, :options
|
56
|
+
def options
|
57
|
+
[
|
58
|
+
['--confuse=enable', '使用该参数,开启工程混淆'],
|
59
|
+
['--confuse=disable', '使用该参数,移除工程混淆配置'],
|
60
|
+
# ['--confuse-folds=folds', '指定额外文件夹检索,多个文件夹使用逗号","分割'],
|
61
|
+
# ['--confuse-all', '忽略黑名单和白名单限制,查询工程所有组件'],
|
62
|
+
].concat(origin_options)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
alias_method :confuse_origin_initialize, :initialize
|
67
|
+
def initialize(argv)
|
68
|
+
confuse_pattern = argv.option('confuse', '') #混淆模式
|
69
|
+
confuse_origin_initialize(argv)
|
70
|
+
instance = Pod::Config.instance
|
71
|
+
instance.confuse_pattern = confuse_pattern
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
42
75
|
end
|
@@ -36,7 +36,7 @@ module Pod
|
|
36
36
|
|
37
37
|
def download_remote_config
|
38
38
|
# 配置文件目录
|
39
|
-
cache_config_file =
|
39
|
+
cache_config_file = Common::Config.instance.cache_config_file
|
40
40
|
|
41
41
|
# 开始下载
|
42
42
|
system("curl -o #{cache_config_file} #{@config}")
|
@@ -50,7 +50,7 @@ module Pod
|
|
50
50
|
|
51
51
|
def copy_local_config
|
52
52
|
# 配置文件目录
|
53
|
-
cache_config_file =
|
53
|
+
cache_config_file = Common::Config.instance.cache_config_file
|
54
54
|
|
55
55
|
# 复制本地文件
|
56
56
|
FileUtils.cp(@config, cache_config_file)
|
@@ -1,15 +1,30 @@
|
|
1
|
+
### common
|
2
|
+
require 'cocoapods-privacy/common/config'
|
3
|
+
require 'cocoapods-privacy/common/BBSpec'
|
4
|
+
require 'cocoapods-privacy/common/BBSpecManager'
|
5
|
+
|
6
|
+
|
7
|
+
### privacy
|
1
8
|
require 'cocoapods-privacy/command/privacy'
|
2
9
|
require 'cocoapods-privacy/command/privacy/config'
|
3
10
|
require 'cocoapods-privacy/command/privacy/install'
|
4
11
|
require 'cocoapods-privacy/command/privacy/spec'
|
5
12
|
require 'cocoapods-privacy/command/install'
|
6
|
-
|
7
13
|
require 'cocoapods-privacy/privacy/privacy_specification_hook'
|
8
14
|
require 'cocoapods-privacy/privacy/privacy_installer_hook'
|
9
15
|
require 'cocoapods-privacy/privacy/PrivacyUtils'
|
10
16
|
require 'cocoapods-privacy/privacy/PrivacyModule'
|
11
17
|
require 'cocoapods-privacy/privacy/PrivacyHunter'
|
12
|
-
require 'cocoapods-privacy/privacy/PrivacyConfig'
|
13
18
|
require 'cocoapods-privacy/privacy/PrivacyLog'
|
14
19
|
|
20
|
+
## mix
|
21
|
+
require 'cocoapods-privacy/command/confuse/spec'
|
22
|
+
require 'cocoapods-privacy/confuse/confuse_installer_hook'
|
23
|
+
require 'cocoapods-privacy/confuse/confuse_specification_hook'
|
24
|
+
require 'cocoapods-privacy/confuse/ConfuseUtils'
|
25
|
+
require 'cocoapods-privacy/confuse/ConfuseModule'
|
26
|
+
require 'cocoapods-privacy/confuse/ConfuseHunter'
|
27
|
+
require 'cocoapods-privacy/confuse/ObjCMethodAPIConverter'
|
28
|
+
require 'cocoapods-privacy/confuse/SwiftCallAssembly'
|
29
|
+
|
15
30
|
|
@@ -0,0 +1,234 @@
|
|
1
|
+
require 'cocoapods-privacy/command'
|
2
|
+
|
3
|
+
KSpecTypePrivacy = 'bb_privacy'
|
4
|
+
KSpecTypeConfuse = 'bb_confuse'
|
5
|
+
|
6
|
+
|
7
|
+
KSource_Files_Key = 'source_files' #不存在单数 source_file
|
8
|
+
KExclude_Files_Key = 'exclude_files' #不存在单数 exclude_file
|
9
|
+
KResource_Bundle_Key = 'resource_bundle' #resource_bundle 和 resource_bundles 这两个参数本质上是一样的,resource_bundle 也能指向多个参数
|
10
|
+
|
11
|
+
class BBRow
|
12
|
+
attr_accessor :content, :is_comment, :is_spec_start, :is_spec_end, :key, :value
|
13
|
+
|
14
|
+
def initialize(content, is_comment=false, is_spec_start=false, is_spec_end=false)
|
15
|
+
@content = content
|
16
|
+
@is_comment = is_comment
|
17
|
+
@is_spec_start = is_spec_start
|
18
|
+
@is_spec_end = is_spec_end
|
19
|
+
|
20
|
+
parse_key_value
|
21
|
+
end
|
22
|
+
|
23
|
+
def parse_key_value
|
24
|
+
# 在这里添加提取 key 和 value 的逻辑
|
25
|
+
if @content.include?('=')
|
26
|
+
key_value_split = @content.split('=')
|
27
|
+
@key = key_value_split[0]
|
28
|
+
@value = key_value_split[1..-1].join('=')
|
29
|
+
else
|
30
|
+
@key = nil
|
31
|
+
@value = nil
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class BBSpec
|
37
|
+
attr_accessor :name, :alias_name, :full_name, :parent, :rows, :sources_files, :exclude_files, :type, :privacy_file, :confuse_file
|
38
|
+
|
39
|
+
def initialize(name,alias_name,full_name,type)
|
40
|
+
@rows = []
|
41
|
+
@name = name
|
42
|
+
@alias_name = alias_name
|
43
|
+
@full_name = full_name
|
44
|
+
@type = type
|
45
|
+
@privacy_file = "Pod/Privacy/#{full_name}/PrivacyInfo.xcprivacy"
|
46
|
+
confuse_file_name = @full_name.tr('.','_')
|
47
|
+
@confuse_file = "Pod/Confuse/#{full_name}/#{confuse_file_name}_Confuse"
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
def uniq_full_name_in_parent(name)
|
52
|
+
names = []
|
53
|
+
@rows.each_with_index do |line, index|
|
54
|
+
if line && line.is_a?(BBSpec)
|
55
|
+
names << line.name
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
#判断names 中是否包含 name,如果包含,那么给name 添加一个 “.diff” 后缀,一直到names 中没有包含name为止
|
60
|
+
while names.include?(name)
|
61
|
+
name = "#{name}.diff"
|
62
|
+
end
|
63
|
+
|
64
|
+
"#{@full_name}.#{name}"
|
65
|
+
end
|
66
|
+
|
67
|
+
# 单独属性转成spec字符串,方便解析
|
68
|
+
def assemble_single_property_to_complex(property_name)
|
69
|
+
property_name += "s" if property_name == KResource_Bundle_Key #检测到单数resource_bundle,直接转成复数,功能一致
|
70
|
+
property_name
|
71
|
+
end
|
72
|
+
|
73
|
+
def privacy_handle(podspec_file_path)
|
74
|
+
@rows.each_with_index do |line, index|
|
75
|
+
if !line || line.is_a?(BBSpec) || !line.key || line.key.empty?
|
76
|
+
next
|
77
|
+
end
|
78
|
+
|
79
|
+
if !line.is_comment && line.key.include?("." + KResource_Bundle_Key)
|
80
|
+
@has_resource_bundle = true
|
81
|
+
elsif !line.is_comment && line.key.include?("." + KSource_Files_Key)
|
82
|
+
@source_files_index = index
|
83
|
+
end
|
84
|
+
end
|
85
|
+
create_file_if_need(podspec_file_path)
|
86
|
+
modify_resource_bundle_if_need(podspec_file_path)
|
87
|
+
end
|
88
|
+
|
89
|
+
# 对应Spec新增隐私文件
|
90
|
+
def create_file_if_need(podspec_file_path)
|
91
|
+
if @source_files_index
|
92
|
+
if is_handle_privacy
|
93
|
+
PrivacyUtils.create_privacy_if_empty(File.join(File.dirname(podspec_file_path), @privacy_file))
|
94
|
+
elsif is_handle_confuse
|
95
|
+
ConfuseUtils.create_confuse_if_empty(File.join(File.dirname(podspec_file_path), "#{@confuse_file}.h"))
|
96
|
+
ConfuseUtils.create_confuse_if_empty(File.join(File.dirname(podspec_file_path), "#{@confuse_file}.swift"))
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def is_handle_privacy
|
102
|
+
@type.include?(KSpecTypePrivacy)
|
103
|
+
end
|
104
|
+
|
105
|
+
def is_handle_confuse
|
106
|
+
@type.include?(KSpecTypeConfuse)
|
107
|
+
end
|
108
|
+
|
109
|
+
# 这里处理所有多行参数的解析,目前处理 source_files\exclude_files\resource_bundle 这三种
|
110
|
+
# 输入格式 ['.source_files':false,'.exclude_files':true......] => true 代表会根据获取的重置属性,需要把多行多余的进行删除
|
111
|
+
# 返回格式 {'.source_files':BBRow,......}
|
112
|
+
def fetch_mul_line_property(propertys_mul_line_hash)
|
113
|
+
property_hash = {}
|
114
|
+
line_processing = nil
|
115
|
+
property_config_processing = nil
|
116
|
+
@rows.each_with_index do |line, index|
|
117
|
+
if !line || line.is_a?(BBSpec) || line.is_comment
|
118
|
+
next
|
119
|
+
end
|
120
|
+
|
121
|
+
property_find = propertys_mul_line_hash.find { |key, _| line.key && line.key.include?(key) } #查找不到返回nil 查到返回数组,key, value 分别在第一和第二个参数
|
122
|
+
if property_find
|
123
|
+
property_config_processing = property_find
|
124
|
+
end
|
125
|
+
|
126
|
+
if property_config_processing
|
127
|
+
begin
|
128
|
+
property_name = property_config_processing.first
|
129
|
+
is_replace_line = property_config_processing.second
|
130
|
+
if line_processing
|
131
|
+
code = "#{line_processing.value}#{line.content}"
|
132
|
+
else
|
133
|
+
code = "#{line.value}"
|
134
|
+
end
|
135
|
+
|
136
|
+
# 清除 content 和 value, 后面会把所有的content 组装起来,多余的内容要清除,避免重复
|
137
|
+
if is_replace_line
|
138
|
+
line.content = ''
|
139
|
+
line.value = nil
|
140
|
+
end
|
141
|
+
|
142
|
+
property_name_complex = assemble_single_property_to_complex(property_name)
|
143
|
+
spec_str = "Pod::Spec.new do |s|; s.#{property_name_complex} = #{code}; end;"
|
144
|
+
RubyVM::InstructionSequence.compile(spec_str)
|
145
|
+
spec = eval(spec_str)
|
146
|
+
property_value = spec.attributes_hash[property_name_complex]
|
147
|
+
rescue SyntaxError, StandardError => e
|
148
|
+
unless line_processing
|
149
|
+
line_processing = line
|
150
|
+
end
|
151
|
+
line_processing.value = code if line_processing #存储当前残缺的value,和后面完整的进行拼接
|
152
|
+
next
|
153
|
+
end
|
154
|
+
|
155
|
+
final_line = (line_processing ? line_processing : line)
|
156
|
+
final_line.value = property_value
|
157
|
+
property_hash[property_name] = final_line
|
158
|
+
line_processing = nil
|
159
|
+
property_config_processing = nil
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
property_hash
|
164
|
+
end
|
165
|
+
|
166
|
+
# 处理字符串或者数组,使其全都转为数组,并转成实际文件夹地址
|
167
|
+
def handle_string_or_array_files(podspec_file_path,line)
|
168
|
+
value = line.value
|
169
|
+
array = fetch_string_or_array_files(podspec_file_path,line)
|
170
|
+
|
171
|
+
files = array.map do |file_path|
|
172
|
+
File.join(File.dirname(podspec_file_path), file_path.strip)
|
173
|
+
end
|
174
|
+
files
|
175
|
+
end
|
176
|
+
|
177
|
+
def fetch_string_or_array_files(podspec_file_path,line)
|
178
|
+
value = line.value
|
179
|
+
if value.is_a?(String) && !value.empty?
|
180
|
+
array = [value]
|
181
|
+
elsif value.is_a?(Array)
|
182
|
+
array = value
|
183
|
+
else
|
184
|
+
array = []
|
185
|
+
end
|
186
|
+
array
|
187
|
+
end
|
188
|
+
|
189
|
+
# 把新增的隐私文件 映射给 podspec && 解析 sources_files && 解析 exclude_files
|
190
|
+
def modify_resource_bundle_if_need(podspec_file_path)
|
191
|
+
if @source_files_index
|
192
|
+
|
193
|
+
# 这里处理所有多行参数的解析,目前处理 source_files\exclude_files\resource_bundle 这三种
|
194
|
+
propertys_mul_line_hash = {}
|
195
|
+
propertys_mul_line_hash[KSource_Files_Key] = false
|
196
|
+
propertys_mul_line_hash[KExclude_Files_Key] = false
|
197
|
+
propertys_mul_line_hash[KResource_Bundle_Key] = false
|
198
|
+
|
199
|
+
property_value_hash = fetch_mul_line_property(propertys_mul_line_hash)
|
200
|
+
property_value_hash.each do |property, line|
|
201
|
+
if property == KSource_Files_Key #处理 source_files
|
202
|
+
@sources_files = handle_string_or_array_files(podspec_file_path,line)
|
203
|
+
# puts "originSource = #{sources_files}"
|
204
|
+
if is_handle_confuse
|
205
|
+
source_array = fetch_string_or_array_files(podspec_file_path,line)
|
206
|
+
source_array.push("#{@confuse_file}.{h,swift}")
|
207
|
+
line.value = source_array.uniq
|
208
|
+
line.content = "#{line.key}= #{line.value}"
|
209
|
+
end
|
210
|
+
elsif property == KExclude_Files_Key #处理 exclude_files
|
211
|
+
@exclude_files = handle_string_or_array_files(podspec_file_path,line)
|
212
|
+
elsif property == KResource_Bundle_Key #处理 原有resource_bundle 合并隐私清单文件映射
|
213
|
+
# 仅在隐私清单时才去解析 resource_bundle
|
214
|
+
privacy_resource_bundle = { "#{full_name}.privacy" => @privacy_file }
|
215
|
+
if is_handle_privacy
|
216
|
+
if @has_resource_bundle
|
217
|
+
merged_resource_bundle = line.value.merge(privacy_resource_bundle)
|
218
|
+
@resource_bundle = merged_resource_bundle
|
219
|
+
line.value = merged_resource_bundle
|
220
|
+
line.content = "#{line.key}= #{line.value}"
|
221
|
+
else # 如果原先没有resource_bundle,需要单独加一行resource_bundle
|
222
|
+
space = PrivacyUtils.count_spaces_before_first_character(rows[@source_files_index].content)
|
223
|
+
line = "#{alias_name}.resource_bundle = #{privacy_resource_bundle}"
|
224
|
+
line = PrivacyUtils.add_spaces_to_string(line,space)
|
225
|
+
row = BBRow.new(line)
|
226
|
+
@rows.insert(@source_files_index+1, row)
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
@@ -0,0 +1,166 @@
|
|
1
|
+
require 'cocoapods-privacy/command'
|
2
|
+
|
3
|
+
module BB
|
4
|
+
class BBSpecManager
|
5
|
+
def initialize(type)
|
6
|
+
@type = type
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
def check(podspec_file_path)
|
11
|
+
# Step 1: 读取podspec
|
12
|
+
lines = read_podspec(podspec_file_path)
|
13
|
+
|
14
|
+
# Step 2: 逐行解析并转位BBRow 模型
|
15
|
+
rows = parse_row(lines)
|
16
|
+
|
17
|
+
# Step 3.1:如果Row 是属于Spec 内,那么聚拢成BBSpec,
|
18
|
+
# Step 3.2:BBSpec 内使用数组存储其Spec 内的行
|
19
|
+
# Step 3.3 在合适位置给每个有效的spec都创建一个 隐私模版,并修改其podspec 引用
|
20
|
+
combin_sepcs_and_rows = combin_sepc_if_need(rows,podspec_file_path)
|
21
|
+
|
22
|
+
# Step 4: 展开修改后的Spec,重新转换成 BBRow
|
23
|
+
rows = unfold_sepc_if_need(combin_sepcs_and_rows)
|
24
|
+
|
25
|
+
# Step 5: 打开隐私模版,并修改其podspec文件,并逐行写入
|
26
|
+
File.open(podspec_file_path, 'w') do |file|
|
27
|
+
# 逐行写入 rows
|
28
|
+
rows.each do |row|
|
29
|
+
file.puts(row.content)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
# Step 6: 获取privacy 相关信息,传递给后续处理
|
35
|
+
hash = fetch_hash(combin_sepcs_and_rows,podspec_file_path).compact
|
36
|
+
filtered_hash = hash.reject { |_, value| value.empty? }
|
37
|
+
filtered_hash
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
def read_podspec(file_path)
|
42
|
+
# puts "read_podspec = #{file_path}"
|
43
|
+
File.readlines(file_path)
|
44
|
+
end
|
45
|
+
|
46
|
+
def parse_row(lines)
|
47
|
+
rows = []
|
48
|
+
code_stack = [] #栈,用来排除if end 等对spec 的干扰
|
49
|
+
|
50
|
+
lines.each do |line|
|
51
|
+
content = line.strip
|
52
|
+
is_comment = content.start_with?('#')
|
53
|
+
is_spec_start = !is_comment && (content.include?('Pod::Spec.new') || content.include?('.subspec'))
|
54
|
+
is_if = !is_comment && content.start_with?('if')
|
55
|
+
is_end = !is_comment && content.start_with?('end')
|
56
|
+
|
57
|
+
# 排除if end 对spec_end 的干扰
|
58
|
+
code_stack.push('spec') if is_spec_start
|
59
|
+
code_stack.push('if') if is_if
|
60
|
+
stack_last = code_stack.last
|
61
|
+
is_spec_end = is_end && stack_last && stack_last == 'spec'
|
62
|
+
is_if_end = is_end && stack_last && stack_last == 'if'
|
63
|
+
code_stack.pop if is_spec_end || is_if_end
|
64
|
+
|
65
|
+
row = BBRow.new(line, is_comment, is_spec_start, is_spec_end)
|
66
|
+
rows << row
|
67
|
+
end
|
68
|
+
rows
|
69
|
+
end
|
70
|
+
|
71
|
+
# 数据格式:
|
72
|
+
# [
|
73
|
+
# BBRow
|
74
|
+
# BBRow
|
75
|
+
# BBSpec
|
76
|
+
# rows
|
77
|
+
# [
|
78
|
+
# BBRow
|
79
|
+
# BBSpec
|
80
|
+
# BBRow
|
81
|
+
# BBRow
|
82
|
+
# ]
|
83
|
+
# BBRow
|
84
|
+
# ......
|
85
|
+
# ]
|
86
|
+
# 合并Row -> Spec(会存在部分行不在Spec中:Spec new 之前的注释)
|
87
|
+
def combin_sepc_if_need(rows,podspec_file_path)
|
88
|
+
spec_stack = []
|
89
|
+
result_rows = []
|
90
|
+
default_name = File.basename(podspec_file_path, File.extname(podspec_file_path))
|
91
|
+
|
92
|
+
rows.each do |row|
|
93
|
+
if row.is_spec_start
|
94
|
+
# 获取父spec
|
95
|
+
parent_spec = spec_stack.last
|
96
|
+
|
97
|
+
# 创建 spec
|
98
|
+
name = row.content.split("'")[1]&.strip || default_name
|
99
|
+
alias_name = row.content.split("|")[1]&.strip
|
100
|
+
full_name = parent_spec ? parent_spec.uniq_full_name_in_parent(name) : name
|
101
|
+
|
102
|
+
spec = BBSpec.new(name,alias_name,full_name,@type)
|
103
|
+
spec.rows << row
|
104
|
+
spec.parent = parent_spec
|
105
|
+
|
106
|
+
# 当存在 spec 时,存储在 spec.rows 中;不存在时,直接存储在外层
|
107
|
+
(parent_spec ? parent_spec.rows : result_rows ) << spec
|
108
|
+
|
109
|
+
# spec 入栈
|
110
|
+
spec_stack.push(spec)
|
111
|
+
elsif row.is_spec_end
|
112
|
+
# 当前 spec 的 rows 加入当前行
|
113
|
+
spec_stack.last&.rows << row
|
114
|
+
|
115
|
+
#执行隐私协议修改
|
116
|
+
spec_stack.last.privacy_handle(podspec_file_path)
|
117
|
+
|
118
|
+
# spec 出栈
|
119
|
+
spec_stack.pop
|
120
|
+
else
|
121
|
+
# 当存在 spec 时,存储在 spec.rows 中;不存在时,直接存储在外层
|
122
|
+
(spec_stack.empty? ? result_rows : spec_stack.last.rows) << row
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
result_rows
|
127
|
+
end
|
128
|
+
|
129
|
+
# 把所有的spec中的rows 全部展开,拼接成一级数组【BBRow】
|
130
|
+
def unfold_sepc_if_need(rows)
|
131
|
+
result_rows = []
|
132
|
+
rows.each do |row|
|
133
|
+
if row.is_a?(BBSpec)
|
134
|
+
result_rows += unfold_sepc_if_need(row.rows)
|
135
|
+
else
|
136
|
+
result_rows << row
|
137
|
+
end
|
138
|
+
end
|
139
|
+
result_rows
|
140
|
+
end
|
141
|
+
|
142
|
+
|
143
|
+
def fetch_hash(rows,podspec_file_path)
|
144
|
+
hash = {}
|
145
|
+
specs = rows.select { |row| row.is_a?(BBSpec) }
|
146
|
+
specs.each do |spec|
|
147
|
+
value = spec.sources_files ? {KSource_Files_Key => spec.sources_files,KExclude_Files_Key => spec.exclude_files || []} : {}
|
148
|
+
if is_handle_privacy
|
149
|
+
hash[File.join(File.dirname(podspec_file_path),spec.privacy_file)] = value
|
150
|
+
elsif is_handle_confuse
|
151
|
+
hash[File.join(File.dirname(podspec_file_path),spec.confuse_file)] = value
|
152
|
+
end
|
153
|
+
hash.merge!(fetch_hash(spec.rows,podspec_file_path))
|
154
|
+
end
|
155
|
+
hash
|
156
|
+
end
|
157
|
+
|
158
|
+
def is_handle_privacy
|
159
|
+
@type.include?(KSpecTypePrivacy)
|
160
|
+
end
|
161
|
+
|
162
|
+
def is_handle_confuse
|
163
|
+
@type.include?(KSpecTypeConfuse)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'cocoapods-privacy/command'
|
2
|
+
require 'digest'
|
3
|
+
|
4
|
+
module Common
|
5
|
+
class Config
|
6
|
+
def initialize()
|
7
|
+
load_config_content_if_exist()
|
8
|
+
end
|
9
|
+
|
10
|
+
def api_template_url
|
11
|
+
load_config_content_if_exist()
|
12
|
+
return @json['api.template.url'] || ""
|
13
|
+
end
|
14
|
+
|
15
|
+
def source_black_list
|
16
|
+
load_config_content_if_exist()
|
17
|
+
return @json['source.black.list'] || []
|
18
|
+
end
|
19
|
+
|
20
|
+
def source_white_list
|
21
|
+
load_config_content_if_exist()
|
22
|
+
return @json['source.white.list'] || []
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.instance
|
26
|
+
@instance ||= new
|
27
|
+
end
|
28
|
+
|
29
|
+
def cache_privacy_fold
|
30
|
+
# 本地缓存目录
|
31
|
+
cache_directory = File.expand_path('~/.cache')
|
32
|
+
|
33
|
+
# 目标文件夹路径
|
34
|
+
target_directory = File.join(cache_directory, 'cocoapods-privacy', 'privacy')
|
35
|
+
|
36
|
+
# 如果文件夹不存在,则创建
|
37
|
+
FileUtils.mkdir_p(target_directory) unless Dir.exist?(target_directory)
|
38
|
+
|
39
|
+
target_directory
|
40
|
+
end
|
41
|
+
|
42
|
+
# etag 文件夹
|
43
|
+
def cache_privacy_etag_fold
|
44
|
+
File.join(cache_privacy_fold,'etag')
|
45
|
+
end
|
46
|
+
|
47
|
+
# config.json 文件
|
48
|
+
def cache_config_file
|
49
|
+
File.join(cache_privacy_fold, 'config.json')
|
50
|
+
end
|
51
|
+
|
52
|
+
# config.json 文件
|
53
|
+
def cache_log_file
|
54
|
+
File.join(cache_privacy_fold, 'privacy.log')
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
def load_config_content_if_exist
|
59
|
+
unless @json
|
60
|
+
if File.exist?(cache_config_file)
|
61
|
+
config_content = File.read(cache_config_file)
|
62
|
+
@json = JSON.parse(config_content)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|