fastlane-plugin-analyze_ios_linkmap 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: cf65a1b127001f7316a0bf431890749143790f804e82d49837757b3fd2279cdc
4
+ data.tar.gz: 925a24e97331807852983ae2fc68417ba3413e53e368ece41769e0a168c23b13
5
+ SHA512:
6
+ metadata.gz: 5ed20a502f407ce23e5fbec2695488fb3bd84eefcfbdc267d26e69ae8e7de2cc8cf161dee73f97045f4199f634cb55853307cfb8cbbf26930cf4f3bd1a3dd203
7
+ data.tar.gz: ba0ad68c8c02b451c7ae4716036821ab35a5bd048aedf3124d70192849badc0f85186f4ba3430cb474778bef749654ba40a1db4c00e189399a6925125307e28b
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2019 xiongzenghui <zxcvb1234001@163.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,71 @@
1
+ # analyze_ios_linkmap plugin
2
+
3
+ [![fastlane Plugin Badge](https://rawcdn.githack.com/fastlane/fastlane/master/fastlane/assets/plugin-badge.svg)](https://rubygems.org/gems/fastlane-plugin-analyze_ios_linkmap)
4
+
5
+ ## Getting Started
6
+
7
+ This project is a [_fastlane_](https://github.com/fastlane/fastlane) plugin. To get started with `fastlane-plugin-analyze_ios_linkmap`, add it to your project by running:
8
+
9
+ ```bash
10
+ fastlane add_plugin analyze_ios_linkmap
11
+ ```
12
+
13
+ ## About analyze_ios_linkmap
14
+
15
+ xx
16
+
17
+ **Note to author:** Add a more detailed description about this plugin here. If your plugin contains multiple actions, make sure to mention them here.
18
+
19
+ ## Example
20
+
21
+ Check out the [example `Fastfile`](fastlane/Fastfile) to see how to use this plugin. Try it by cloning the repo, running `fastlane install_plugins` and `bundle exec fastlane test`.
22
+
23
+ ```ruby
24
+ lane :test do
25
+ # eg1:
26
+ analyze_ios_linkmap(
27
+ filepath: '/Users/xiongzenghui/collect_rubygems/fastlane-plugins/fastlane-plugin-analyze_ios_linkmap/spec/demo-LinkMap.txt'
28
+ )
29
+ pp Fastlane::Actions.lane_context[Fastlane::Actions::ShatedValues::ANALYZE_IOS_LINKMAP_PARED_HASH]
30
+ pp Fastlane::Actions.lane_context[Fastlane::Actions::ShatedValues::ANALYZE_IOS_LINKMAP_PARED_JSON]
31
+
32
+ # eg2:
33
+ analyze_ios_linkmap(
34
+ filepath: '/Users/xiongzenghui/Desktop/osee2unifiedRelease-LinkMap-normal-arm64.txt',
35
+ search_symbol: 'TDATEvo'
36
+ )
37
+ pp Fastlane::Actions.lane_context[Fastlane::Actions::ShatedValues::ANALYZE_IOS_LINKMAP_SEARCH_SYMBOL]
38
+ end
39
+
40
+ ```
41
+
42
+
43
+
44
+ ## Run tests for this plugin
45
+
46
+ To run both the tests, and code style validation, run
47
+
48
+ ```
49
+ rake
50
+ ```
51
+
52
+ To automatically fix many of the styling issues, use
53
+ ```
54
+ rubocop -a
55
+ ```
56
+
57
+ ## Issues and Feedback
58
+
59
+ For any other issues and feedback about this plugin, please submit it to this repository.
60
+
61
+ ## Troubleshooting
62
+
63
+ If you have trouble using plugins, check out the [Plugins Troubleshooting](https://docs.fastlane.tools/plugins/plugins-troubleshooting/) guide.
64
+
65
+ ## Using _fastlane_ Plugins
66
+
67
+ For more information about how the `fastlane` plugin system works, check out the [Plugins documentation](https://docs.fastlane.tools/plugins/create-plugin/).
68
+
69
+ ## About _fastlane_
70
+
71
+ _fastlane_ is the easiest way to automate beta deployments and releases for your iOS and Android apps. To learn more, check out [fastlane.tools](https://fastlane.tools).
@@ -0,0 +1,79 @@
1
+ require 'fastlane/action'
2
+ require_relative '../helper/analyze_ios_linkmap_helper'
3
+
4
+ module Fastlane
5
+ module Actions
6
+ module ShatedValues
7
+ ANALYZE_IOS_LINKMAP_SEARCH_SYMBOL = :ANALYZE_IOS_LINKMAP_SEARCH_SYMBOL
8
+ ANALYZE_IOS_LINKMAP_PARED_HASH = :ANALYZE_IOS_LINKMAP_PARED_HASH
9
+ ANALYZE_IOS_LINKMAP_PARED_JSON = :ANALYZE_IOS_LINKMAP_PARED_JSON
10
+ end
11
+
12
+ class AnalyzeIosLinkmapAction < Action
13
+ def self.run(params)
14
+ filepath = params[:filepath]
15
+ search_symbol = params[:search_symbol]
16
+
17
+ parser = Fastlane::Helper::LinkMap::Parser.new(filepath)
18
+
19
+ if search_symbol
20
+ Fastlane::Actions.lane_context[Fastlane::Actions::ShatedValues::ANALYZE_IOS_LINKMAP_SEARCH_SYMBOL] = []
21
+ parser.pretty_hash[:librarys].each do |lib|
22
+ lib[:objects].each do |obj|
23
+ obj[:symbols].each do |symol|
24
+ next unless symol[:name].include?(search_symbol)
25
+
26
+ Fastlane::Actions.lane_context[Fastlane::Actions::ShatedValues::ANALYZE_IOS_LINKMAP_SEARCH_SYMBOL] << {
27
+ library: lib[:library],
28
+ object_file: obj[:object],
29
+ symbol: symol[:name]
30
+ }
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ Fastlane::Actions.lane_context[Fastlane::Actions::ShatedValues::ANALYZE_IOS_LINKMAP_PARED_HASH] = parser.pretty_hash
37
+ Fastlane::Actions.lane_context[Fastlane::Actions::ShatedValues::ANALYZE_IOS_LINKMAP_PARED_JSON] = parser.pretty_json
38
+ end
39
+
40
+ def self.available_options
41
+ [
42
+ FastlaneCore::ConfigItem.new(
43
+ key: :filepath,
44
+ description: "/your/path/to/linkmap.txt",
45
+ verify_block: ->(value) {
46
+ UI.user_error("❌ filepath not pass") unless value
47
+ UI.user_error!("❌ filepath #{value} not exist") unless File.exist?(value)
48
+ }
49
+ ),
50
+ FastlaneCore::ConfigItem.new(
51
+ key: :search_symbol,
52
+ description: "search your give symbol in linkmap.txt from what library",
53
+ optional: true
54
+ )
55
+ ]
56
+ end
57
+
58
+ def self.description
59
+ "iOS parse linkmap.txt to ruby Hash or JSON"
60
+ end
61
+
62
+ def self.authors
63
+ ["xiongzenghui"]
64
+ end
65
+
66
+ def self.return_value
67
+ # If your method provides a return value, you can describe here what it does
68
+ end
69
+
70
+ def self.details
71
+ "iOS parse linkmap.txt to ruby Hash"
72
+ end
73
+
74
+ def self.is_supported?(platform)
75
+ :ios == platform
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,42 @@
1
+ require 'fastlane_core/ui/ui'
2
+
3
+ module Fastlane
4
+ UI = FastlaneCore::UI unless Fastlane.const_defined?("UI")
5
+ module Helper
6
+ module LinkMap
7
+ class FileHelper
8
+ def self.file_size(file_path)
9
+ return 0 unless File.exist?(file_path)
10
+
11
+ base = File.basename(file_path)
12
+ return 0 if ['.', '..'].include?(base)
13
+
14
+ total = 0
15
+ if File.directory?(file_path)
16
+ Dir.glob(File.expand_path('*', file_path)).each do |f|
17
+ # pp f
18
+ total += file_size(f)
19
+ end
20
+ else
21
+ size = File.stat(file_path).size
22
+ total += size
23
+ end
24
+
25
+ total
26
+ end
27
+
28
+ def self.format_size(bytes)
29
+ return '0 B' unless bytes
30
+ return '0 B' if bytes.zero?
31
+
32
+ k = 1024
33
+ suffix = %w[B KB MB GB TB PB EB ZB YB]
34
+ i = (Math.log(bytes) / Math.log(k)).floor
35
+ base = (k ** i).to_f
36
+ num = (bytes / base).round(2)
37
+ "#{num} " + suffix[i]
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,464 @@
1
+ require 'fastlane_core/ui/ui'
2
+
3
+ module Fastlane
4
+ UI = FastlaneCore::UI unless Fastlane.const_defined?("UI")
5
+ module Helper
6
+ module LinkMap
7
+ require 'pp'
8
+
9
+ # Symbols:
10
+ # Address Size File Name
11
+ # 0x100001710 0x00000039 [ 2] -[ViewController viewDidLoad]
12
+ Symbol = Struct.new(:address, :size, :object_file_id, :name)
13
+
14
+ # Dead Stripped Symbols:
15
+ # Size File Name
16
+ # <<dead>> 0x00000018 [ 2] CIE
17
+ DeadStrippedSymbol = Struct.new(:size, :object_file_id, :name)
18
+
19
+ # Sections:
20
+ # Address Size Segment Section
21
+ # 0x100001710 0x00000333 __TEXT __text
22
+ Section = Struct.new(:section, :segment, :start_addr, :end_addr, :symbol_size, :residual_size) do
23
+ def key
24
+ "#{segment}:#{section}".to_sym
25
+ end
26
+
27
+ def parse_segment
28
+ key.to_s.split(':')[0].to_sym
29
+ end
30
+ end
31
+
32
+ # Linkmap.txt 中, 没有直接给出, 只能由【所有的 Section】统计得出
33
+ Segment = Struct.new(:name, :symbol_size, :residual_size)
34
+
35
+ #
36
+ #<FastlaneCore::Helper::LinkMap::ObjectFile:0x007ff93ec4fc90
37
+ # @file_id=39,
38
+ # object="ViewController.o",
39
+ # @framework=false,
40
+ # @library="libbangcle_crypto_tool.a",
41
+ # @symbols=[
42
+ # <struct FastlaneCore::Helper::LinkMap::Symbol
43
+ # address=4294976749,
44
+ # size=15,
45
+ # object_file_id=2,
46
+ # name="literal string: ViewController"
47
+ # >,
48
+ # <struct FastlaneCore::Helper::LinkMap::Symbol
49
+ # address=4294974150,
50
+ # size=12,
51
+ # object_file_id=2,
52
+ # name="literal string: viewDidLoad"
53
+ # >
54
+ # ]
55
+ # >
56
+ ObjectFile = Struct.new(:file_id, :object, :library, :framework, :symbols, :size, :dead_symbol_size)
57
+
58
+ #
59
+ # "AFNetworking"=>
60
+ # <struct FastlaneCore::Helper::LinkMap::Library
61
+ # name="AFNetworking",
62
+ # size=0,
63
+ # object_file_ids=[23,24,25,26,27,28,29,30],
64
+ # dead_symbol_size=0,
65
+ # pod_name="AFNetworking"
66
+ # >
67
+ #
68
+ Library = Struct.new(:name, :size, :object_file_ids, :dead_symbol_size, :pod_name)
69
+
70
+ class Parser
71
+ attr_accessor(:object_map, :library_map, :section_map, :segment_map)
72
+
73
+ def initialize(filepath)
74
+ @filepath = filepath
75
+
76
+ @object_map = {}
77
+ @library_map = {}
78
+ @section_map = {}
79
+ @segment_map = {} # 根据 @section_map 统计【所有的 section】得出
80
+
81
+ parse
82
+ end
83
+
84
+ def parse
85
+ # 读取 Linkmap.txt 【每一行】进行解析
86
+ File.foreach(@filepath).with_index do |line, line_num|
87
+ begin
88
+ unless line.valid_encoding?
89
+ line = line.encode("UTF-16", :invalid => :replace, :replace => "?").encode('UTF-8')
90
+ end
91
+
92
+ if line.start_with? "#"
93
+ if line.start_with? "# Object files:" #=> 初始化 @object_map
94
+ @subparser = :parse_object_files
95
+ elsif line.start_with? "# Sections:" #=> 初始化 @section_map
96
+ @subparser = :parse_sections
97
+ elsif line.start_with? "# Symbols:" #=> 解析得到每一个 symbol 【占用】大小
98
+ @subparser = :parse_symbols
99
+ elsif line.start_with? '# Dead Stripped Symbols:' #=> 解析得到 dead strpped 【废弃】大小
100
+ @subparser = :parse_dead
101
+ end
102
+ else
103
+ send(@subparser, line) #=> self.func(line)
104
+ end
105
+ rescue => e
106
+ UI.error "Exception on Link map file line #{line_num}"
107
+ UI.message "Content is: "
108
+ UI.message line
109
+ end
110
+ end
111
+ # puts "There are #{@section_map.values.map{|value| value[:residual_size]}.inject(:+)} Byte in some section can not be analyze"
112
+ end
113
+
114
+ def parse_object_files(line)
115
+ if line =~ %r(\[(.*)\].*\/(.*)\((.*)\))
116
+ # Object files:
117
+ # [ 5] /Users/xiongzenghui/Desktop/launching_time/osee2unified/osee2unified/Pods/BangcleCryptoTool/BangcleCryptoTool/libs/libbangcle_crypto_tool.a(aes.o)
118
+ # [ 6] /Users/xiongzenghui/Desktop/launching_time/osee2unified/osee2unified/Pods/BangcleCryptoTool/BangcleCryptoTool/libs/libbangcle_crypto_tool.a(crypto.o)
119
+ # [ 7] /Users/xiongzenghui/Desktop/launching_time/osee2unified/osee2unified/Pods/BangcleCryptoTool/BangcleCryptoTool/libs/libbangcle_crypto_tool.a(des.o)
120
+ # ...............
121
+ # [ 23] /Users/xxx/ci-jenkins/workspace/xxx-iOS-module/VenomShellProject/osee2unified/Pods/AFNetworking/AFNetworking.framework/AFNetworking(AFAutoPurgingImageCache.o)
122
+ # [ 24] /Users/xxx/ci-jenkins/workspace/xxx-iOS-module/VenomShellProject/osee2unified/Pods/AFNetworking/AFNetworking.framework/AFNetworking(AFHTTPSessionManager.o)
123
+ # [ 25] /Users/xxx/ci-jenkins/workspace/xxx-iOS-module/VenomShellProject/osee2unified/Pods/AFNetworking/AFNetworking.framework/AFNetworking(AFImageDownloader.o)
124
+ # ...........
125
+
126
+ # 1.
127
+ objc_file_id = $1.to_i #=> 6 , 23
128
+ library_name = $2 #=> libbangcle_crypto_tool.a , AFNetworking
129
+ object_file = $3 #=> crypto.o , AFAutoPurgingImageCache.o
130
+
131
+ # 2.
132
+ of = ObjectFile.new(
133
+ objc_file_id,
134
+ object_file,
135
+ library_name,
136
+ if line.include?('.framework')
137
+ true
138
+ else
139
+ false
140
+ end,
141
+ Array.new,
142
+ 0,
143
+ 0
144
+ )
145
+
146
+ # 3. 保存解析 xx.o (object file) 的数据
147
+ @object_map[objc_file_id] = of
148
+
149
+ # 4. 创建【静态库 library】对应的实体对象
150
+ library = @library_map[library_name]
151
+ library ||= Library.new(library_name, 0, [], 0, '')
152
+
153
+ # 5. 【追加】 xx.o 文件位于 ``# Object Files`` 后面的 [ n] 标号
154
+ library.object_file_ids << objc_file_id
155
+
156
+ # 6. 确认 library 的 pod_name 名字
157
+ if line.include?('/Pods/')
158
+ # [ 23] /Users/xxx/ci-jenkins/workspace/xxx-iOS-module/VenomShellProject/osee2unified/Pods/AFNetworking/AFNetworking.framework/AFNetworking(AFAutoPurgingImageCache.o)
159
+ divstr = line.split('/Pods/').last #=> AFNetworking/AFNetworking.framework/AFNetworking(AFAutoPurgingImageCache.o
160
+ pod_name = divstr.split('/').first #=> AFNetworking
161
+ library.pod_name = pod_name
162
+ else
163
+ library.pod_name = ''
164
+ end
165
+
166
+ # 7.
167
+ @library_map[library_name] = library
168
+ elsif line =~ %r(\[(.*)\].*\/(.*))
169
+ # [ 3] /SomePath/Release-iphoneos/CrashDemo.build/Objects-normal/arm64/main.o
170
+ # [100] /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.3.sdk/System/Library/Frameworks/UIKit.framework/UIKit.tbd
171
+ # [9742] /SomePath/Pods/du.framework/du
172
+ # [8659] /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphoneos/libswiftDispatch.dylib
173
+
174
+ # 1.
175
+ objc_file_id = $1.to_i #=> 3
176
+ object_file = $2 #=> main.o
177
+
178
+ # 2.
179
+ library_name = ''
180
+ if line.include?('.framework') && !object_file.include?('.') #=> /path/to/du.framework/du 【用户】动态库
181
+ library_name = object_file
182
+ else
183
+ if line.end_with?('.a')
184
+ library_name = object_file
185
+ else
186
+ library_name = if object_file.end_with?('.tbd')
187
+ 'tdb'
188
+ elsif object_file.end_with?('.dylib')
189
+ 'dylib'
190
+ elsif object_file.end_with?('.o')
191
+ 'main'
192
+ else
193
+ 'system'
194
+ end
195
+ end
196
+ end
197
+
198
+ # 3.
199
+ of = ObjectFile.new(
200
+ objc_file_id,
201
+ object_file,
202
+ library_name,
203
+ if line.include?('.framework') && !object_file.include?('.')
204
+ true
205
+ else
206
+ false
207
+ end,
208
+ Array.new,
209
+ 0,
210
+ 0
211
+ )
212
+
213
+ # 4.
214
+ @object_map[objc_file_id] = of
215
+ # puts "#{objc_file_id} -- #{library_name}"
216
+
217
+ # 5.
218
+ library = @library_map[library_name]
219
+ library ||= Library.new(library_name, 0, [], 0, '')
220
+
221
+ # 6.
222
+ library.object_file_ids << objc_file_id
223
+
224
+ # 7.
225
+ @library_map[library_name] = library
226
+ elsif line =~ /\[(.*)\]\s*([\w\s]+)/
227
+ # Sample:
228
+ # [ 0] linker synthesized
229
+ # [ 1] dtrace
230
+
231
+ # 1.
232
+ objc_file_id = $1.to_i
233
+
234
+ # 2.
235
+ of = ObjectFile.new(
236
+ objc_file_id,
237
+ $2,
238
+ '',
239
+ false,
240
+ Array.new,
241
+ 0,
242
+ 0
243
+ )
244
+
245
+ # 3.
246
+ @object_map[objc_file_id] = of
247
+ end
248
+ end
249
+
250
+ def parse_sections(line)
251
+ # Sections:
252
+ # Address Size Segment Section
253
+ # 0x1000048A0 0x055656A8 __TEXT __text
254
+ # 0x105569F48 0x000090E4 __TEXT __stubs
255
+ # 0x10557302C 0x000079D4 __TEXT __stub_helper
256
+ # 0x10557AA00 0x002D4E1A __TEXT __cstring
257
+ #
258
+
259
+ lines = line.split(' ').each(&:strip)
260
+ section_name = lines[3]
261
+ segment_name = lines[2]
262
+ start_addr = lines.first.to_i(16)
263
+ end_addr = start_addr + lines[1].to_i(16)
264
+ residual_size = lines[1].to_i(16)
265
+
266
+ section = Section.new(
267
+ section_name,
268
+ segment_name,
269
+ start_addr,
270
+ end_addr,
271
+ 0,
272
+ residual_size
273
+ )
274
+
275
+ # 【section name】may be dulicate in different segment
276
+ # 所以使用 segment_name + section_name 作为 map 的 key 存储
277
+ @section_map[section.key] = section
278
+ end
279
+
280
+ def parse_symbols(line)
281
+ # Symbols:
282
+ # Address Size File Name
283
+ # 0x1000048A0 0x000000A4 [ 2] _main
284
+ # 0x100004944 0x00000028 [ 5] _Bangcle_WB_AES_encrypt
285
+
286
+ if line =~ %r(^0x(.+?)\s+0x(.+?)\s+\[(.+?)\]\s(.*))
287
+ # 1.
288
+ symbol_address = $1.to_i(16) #=> Address
289
+ symbol_size = $2.to_i(16) #=> Size
290
+ object_file_id = $3.to_i #=> File
291
+ symbol_name = $4 #=> Name
292
+
293
+ # 2.
294
+ object_file = @object_map[object_file_id]
295
+
296
+ # 3.
297
+ unless object_file
298
+ UI.error "#{line.inspect} can not found object file"
299
+ return
300
+ end
301
+
302
+ # 4.
303
+ symbol = Symbol.new(
304
+ symbol_address,
305
+ symbol_size,
306
+ object_file_id,
307
+ symbol_name
308
+ )
309
+
310
+ # 5. 追加【symbol】符号
311
+ object_file.symbols.push(symbol)
312
+
313
+ # 6. 统计【Object File】总大小
314
+ object_file.size += symbol_size
315
+
316
+ # 7. 统计【library/framework】总大小
317
+ library = @library_map[object_file.library]
318
+ library.size += symbol_size if library
319
+
320
+ # 8. 统计【segment】总大小
321
+ sections = @section_map.detect do |seg_sec_name, sec|
322
+ if sec
323
+ (sec.start_addr...sec.end_addr).include?(symbol_address)
324
+ else
325
+ false
326
+ end
327
+ end
328
+ # pp "⚠️ seg_sec_names=#{seg_sec_names}"
329
+
330
+ if sections
331
+ section = sections[1]
332
+ segment_name = section.parse_segment
333
+ segment = @segment_map[segment_name]
334
+ # pp "⚠️ segment_name=#{segment_name}"
335
+
336
+ unless segment
337
+ segment = Segment.new(segment_name, symbol_size, symbol_size)
338
+ else
339
+ segment.symbol_size += symbol_size
340
+ segment.residual_size += symbol_size
341
+ end
342
+ # pp "⚠️ #{segment.name} #{segment.symbol_size} - #{segment.residual_size}"
343
+ @segment_map[segment_name] = segment
344
+ end
345
+ else
346
+ UI.error "#{line.inspect} can not match symbol regular"
347
+ end
348
+ end
349
+
350
+ def parse_dead(line)
351
+ # Dead Stripped Symbols:
352
+ # Size File Name
353
+ # <<dead>> 0x00000028 [ 2] literal string: com.xxx.audioBook.notifications.start
354
+ # <<dead>> 0x00000029 [ 2] literal string: com.xxx.audioBook.notifications.stoped
355
+ # <<dead>> 0x0000002A [ 2] literal string: com.xxx.audioBook.notificaitons.loading
356
+ # <<dead>> 0x0000002A [ 2] literal string: com.xxx.audioBook.notificaitons.palying
357
+ # <<dead>> 0x0000002D [ 2] literal string: com.xxx.audioBook.notificaitons.paySuccess
358
+ # <<dead>> 0x00000006 [ 2] literal string: appId
359
+ # <<dead>> 0x00000008 [ 2] literal string: fakeURL
360
+ # <<dead>> 0x00000007 [ 2] literal string: 300300
361
+
362
+ if line =~ %r(^<<dead>>\s+0x(.+?)\s+\[(.+?)\]\w*)
363
+ size = $1.to_i(16)
364
+ file = $2.to_i
365
+
366
+ object_file = @object_map[file]
367
+ return unless object_file
368
+
369
+ # 累加 xx.o 的 dead symbol size
370
+ object_file.dead_symbol_size += size
371
+
372
+ # 累加 library(xx.o) 的 dead symbol size
373
+ @library_map[object_file.library].dead_symbol_size += size
374
+ end
375
+ end
376
+
377
+ def pretty_json
378
+ result = pretty_hash
379
+ unless result
380
+ UI.user_error!("❌ LinkMap parsed failed!")
381
+ end
382
+ JSON.pretty_generate(result)
383
+ end
384
+
385
+ def pretty_hash
386
+ UI.user_error!("❌ #{@filepath} not pass") unless @filepath
387
+ UI.user_error!("❌ #{@filepath} not exist") unless File.exist?(@filepath)
388
+
389
+ result
390
+ end
391
+
392
+ def result
393
+ # 1. cache
394
+ return @result if @result
395
+
396
+ # 2. sort object_map[i].ObjectFile.symbols
397
+ @object_map.each do |ofid, object|
398
+ next unless object.symbols
399
+
400
+ object.symbols.sort! do |sym1, sym2|
401
+ sym2[:size] <=> sym1[:size]
402
+ end
403
+ end
404
+
405
+ # 3. linkmap.txt 所有的 symbol 总大小
406
+ total_size = @library_map.values.map(&:size).inject(:+)
407
+ total_dead_size = @library_map.values.map(&:dead_symbol_size).inject(:+)
408
+
409
+ # 4.
410
+ library_map_values = @library_map.values.sort do |a, b|
411
+ b.size <=> a.size
412
+ end
413
+ library_map_values.compact!
414
+
415
+ # 5.
416
+ library_maps = library_map_values.map do |lib|
417
+ pod_name = lib.name
418
+ unless lib.pod_name.empty?
419
+ pod_name = lib.pod_name
420
+ end
421
+ # pp "pod_name=#{pod_name}"
422
+
423
+ {
424
+ library: lib.name,
425
+ pod: pod_name,
426
+ total: lib.size,
427
+ format_total: Fastlane::Helper::LinkMap::FileHelper.format_size(lib.size),
428
+ total_dead: lib.dead_symbol_size,
429
+ format_total_dead: Fastlane::Helper::LinkMap::FileHelper.format_size(lib.dead_symbol_size),
430
+ objects: lib.object_file_ids.map do |object_file_id|
431
+ # Struct.new(:file_id, :object, :library, :framework, :symbols, :size, :dead_symbol_size)
432
+ object_file = @object_map[object_file_id]
433
+ if object_file
434
+ {
435
+ object: object_file.object,
436
+ symbols: object_file.symbols.map do |symb|
437
+ {
438
+ name: symb.name,
439
+ total: symb.size,
440
+ format_total: Fastlane::Helper::LinkMap::FileHelper.format_size(symb.size),
441
+ }
442
+ end
443
+ }
444
+ else
445
+ nil
446
+ end
447
+ end
448
+ }
449
+ end
450
+
451
+ # 6.
452
+ @result = {
453
+ total: total_size,
454
+ format_total: Fastlane::Helper::LinkMap::FileHelper.format_size(total_size),
455
+ total_dead: total_dead_size,
456
+ format_total_dead: Fastlane::Helper::LinkMap::FileHelper.format_size(total_dead_size),
457
+ librarys: library_maps
458
+ }
459
+ @result
460
+ end
461
+ end
462
+ end
463
+ end
464
+ end
@@ -0,0 +1,5 @@
1
+ module Fastlane
2
+ module AnalyzeIosLinkmap
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,16 @@
1
+ require 'fastlane/plugin/analyze_ios_linkmap/version'
2
+
3
+ module Fastlane
4
+ module AnalyzeIosLinkmap
5
+ # Return all .rb files inside the "actions" and "helper" directory
6
+ def self.all_classes
7
+ Dir[File.expand_path('**/{actions,helper}/*.rb', File.dirname(__FILE__))]
8
+ end
9
+ end
10
+ end
11
+
12
+ # By default we want to import all available actions and helpers
13
+ # A plugin can contain any number of actions and plugins
14
+ Fastlane::AnalyzeIosLinkmap.all_classes.each do |current|
15
+ require current
16
+ end
metadata ADDED
@@ -0,0 +1,175 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fastlane-plugin-analyze_ios_linkmap
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - xiongzenghui
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-08-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: pry
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec_junit_formatter
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '='
88
+ - !ruby/object:Gem::Version
89
+ version: 0.49.1
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '='
95
+ - !ruby/object:Gem::Version
96
+ version: 0.49.1
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop-require_tools
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: simplecov
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: fastlane
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: 2.128.1
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: 2.128.1
139
+ description:
140
+ email: zxcvb1234001@163.com
141
+ executables: []
142
+ extensions: []
143
+ extra_rdoc_files: []
144
+ files:
145
+ - LICENSE
146
+ - README.md
147
+ - lib/fastlane/plugin/analyze_ios_linkmap.rb
148
+ - lib/fastlane/plugin/analyze_ios_linkmap/actions/analyze_ios_linkmap_action.rb
149
+ - lib/fastlane/plugin/analyze_ios_linkmap/helper/analyze_ios_file_helper.rb
150
+ - lib/fastlane/plugin/analyze_ios_linkmap/helper/analyze_ios_linkmap_helper.rb
151
+ - lib/fastlane/plugin/analyze_ios_linkmap/version.rb
152
+ homepage: https://github.com/xzhhe/fastlane-plugin-analyze_ios_linkmap
153
+ licenses:
154
+ - MIT
155
+ metadata: {}
156
+ post_install_message:
157
+ rdoc_options: []
158
+ require_paths:
159
+ - lib
160
+ required_ruby_version: !ruby/object:Gem::Requirement
161
+ requirements:
162
+ - - ">="
163
+ - !ruby/object:Gem::Version
164
+ version: '0'
165
+ required_rubygems_version: !ruby/object:Gem::Requirement
166
+ requirements:
167
+ - - ">="
168
+ - !ruby/object:Gem::Version
169
+ version: '0'
170
+ requirements: []
171
+ rubygems_version: 3.0.1
172
+ signing_key:
173
+ specification_version: 4
174
+ summary: iOS parse linkmap.txt to ruby Hash
175
+ test_files: []