fastlane-plugin-analyze_ios_linkmap 0.1.1 → 0.1.2
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 +56 -17
- data/lib/fastlane/plugin/analyze_ios_linkmap/actions/analyze_ios_linkmap_action.rb +56 -47
- data/lib/fastlane/plugin/analyze_ios_linkmap/helper/analyze_ios_linkmap_parser.rb +299 -0
- data/lib/fastlane/plugin/analyze_ios_linkmap/helper/linkmap_dead_stripped_symbol.rb +38 -0
- data/lib/fastlane/plugin/analyze_ios_linkmap/helper/linkmap_helper.rb +7 -0
- data/lib/fastlane/plugin/analyze_ios_linkmap/helper/linkmap_library.rb +55 -0
- data/lib/fastlane/plugin/analyze_ios_linkmap/helper/linkmap_object_file.rb +143 -0
- data/lib/fastlane/plugin/analyze_ios_linkmap/helper/linkmap_section.rb +71 -0
- data/lib/fastlane/plugin/analyze_ios_linkmap/helper/linkmap_segment.rb +31 -0
- data/lib/fastlane/plugin/analyze_ios_linkmap/helper/linkmap_symbol.rb +41 -0
- data/lib/fastlane/plugin/analyze_ios_linkmap/version.rb +1 -1
- metadata +11 -4
- data/lib/fastlane/plugin/analyze_ios_linkmap/helper/analyze_ios_linkmap_helper.rb +0 -493
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: c3bdbca21db75b21aaf970b4116c66ce3bfb4bfda14b606c1eddcc08748b2396
         | 
| 4 | 
            +
              data.tar.gz: 40fd82b671e199e38a1215be9a665e08a312440c502e83aacd30c654a3fba9e5
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 26ddfed8795e9b4416a4ea3fb03dc2eaa013c84ab2587537612b4b0b0edeb4b77685fc9edd361be4301edf345bb311d3448c7fd610a7d986982261cfc15270d3
         | 
| 7 | 
            +
              data.tar.gz: 27b1cb171f8990d3a4b5f8068f26b67d3203e3a9dbefc76abd1463c53fc00b5d693fc5ddfcbbd8d52d44c28d7119121093c2bf3087bc48733bf4e6a4d61a16c8
         | 
    
        data/README.md
    CHANGED
    
    | @@ -12,33 +12,72 @@ fastlane add_plugin analyze_ios_linkmap | |
| 12 12 |  | 
| 13 13 | 
             
            ## About analyze_ios_linkmap
         | 
| 14 14 |  | 
| 15 | 
            -
            xx
         | 
| 16 | 
            -
             | 
| 17 15 | 
             
            **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 16 |  | 
| 19 17 | 
             
            ## Example
         | 
| 20 18 |  | 
| 21 19 | 
             
            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 20 |  | 
| 21 | 
            +
            ### Eg1: 默认解析一个 linkmap.txt
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            ```ruby
         | 
| 24 | 
            +
            path = '/Users/xiongzenghui/Desktop/Demo-LinkMap-normal-arm64.txt'
         | 
| 25 | 
            +
            Fastlane::Actions::AnalyzeIosLinkmapAction.run( file_path: path )
         | 
| 26 | 
            +
            pp Fastlane::Actions.lane_context[Fastlane::Actions::ShatedValues::ANALYZE_IOS_LINKMAP_PARSED_HASH]
         | 
| 27 | 
            +
            pp Fastlane::Actions.lane_context[Fastlane::Actions::ShatedValues::ANALYZE_IOS_LINKMAP_PARSED_JSON]
         | 
| 28 | 
            +
            ```
         | 
| 29 | 
            +
             | 
| 30 | 
            +
            ### Eg2: 显示所有的 object file
         | 
| 31 | 
            +
             | 
| 32 | 
            +
            ```ruby
         | 
| 33 | 
            +
            path = '/Users/xiongzenghui/Desktop/Demo-LinkMap-normal-arm64.txt'
         | 
| 34 | 
            +
            Fastlane::Actions::AnalyzeIosLinkmapAction.run(
         | 
| 35 | 
            +
              file_path: path,
         | 
| 36 | 
            +
              all_objects: true
         | 
| 37 | 
            +
            )
         | 
| 38 | 
            +
            pp Fastlane::Actions.lane_context[Fastlane::Actions::ShatedValues::ANALYZE_IOS_LINKMAP_PARSED_HASH]
         | 
| 39 | 
            +
            pp Fastlane::Actions.lane_context[Fastlane::Actions::ShatedValues::ANALYZE_IOS_LINKMAP_PARSED_JSON]
         | 
| 40 | 
            +
            ```
         | 
| 41 | 
            +
             | 
| 42 | 
            +
            ### Eg3: 显示所有的 symbol
         | 
| 43 | 
            +
             | 
| 23 44 | 
             
            ```ruby
         | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 26 | 
            -
               | 
| 27 | 
            -
             | 
| 28 | 
            -
               | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
                search_symbol: 'TDATEvo'
         | 
| 36 | 
            -
              )
         | 
| 37 | 
            -
              pp Fastlane::Actions.lane_context[Fastlane::Actions::ShatedValues::ANALYZE_IOS_LINKMAP_SEARCH_SYMBOL]
         | 
| 38 | 
            -
            end
         | 
| 45 | 
            +
            path = '/Users/xiongzenghui/Desktop/Demo-LinkMap-normal-arm64.txt'
         | 
| 46 | 
            +
            Fastlane::Actions::AnalyzeIosLinkmapAction.run(
         | 
| 47 | 
            +
              file_path: path,
         | 
| 48 | 
            +
              all_objects: true,
         | 
| 49 | 
            +
              all_symbols: true
         | 
| 50 | 
            +
            )
         | 
| 51 | 
            +
            pp Fastlane::Actions.lane_context[Fastlane::Actions::ShatedValues::ANALYZE_IOS_LINKMAP_PARSED_HASH]
         | 
| 52 | 
            +
            pp Fastlane::Actions.lane_context[Fastlane::Actions::ShatedValues::ANALYZE_IOS_LINKMAP_PARSED_JSON]
         | 
| 53 | 
            +
            ```
         | 
| 54 | 
            +
             | 
| 55 | 
            +
            ### Eg4: 根据 podspec name 进行合并
         | 
| 39 56 |  | 
| 57 | 
            +
            ```ruby
         | 
| 58 | 
            +
            path = '/Users/xiongzenghui/Desktop/Demo-LinkMap-normal-arm64.txt'
         | 
| 59 | 
            +
            Fastlane::Actions::AnalyzeIosLinkmapAction.run(
         | 
| 60 | 
            +
              file_path: path,
         | 
| 61 | 
            +
              all_objects: false,
         | 
| 62 | 
            +
              all_symbols: false,
         | 
| 63 | 
            +
              merge_by_pod: true
         | 
| 64 | 
            +
            )
         | 
| 65 | 
            +
            pp Fastlane::Actions.lane_context[Fastlane::Actions::ShatedValues::ANALYZE_IOS_LINKMAP_PARSED_HASH]
         | 
| 66 | 
            +
            pp Fastlane::Actions.lane_context[Fastlane::Actions::ShatedValues::ANALYZE_IOS_LINKMAP_PARSED_JSON]
         | 
| 67 | 
            +
            pp Fastlane::Actions.lane_context[Fastlane::Actions::ShatedValues::ANALYZE_IOS_LINKMAP_PARSED_MERGE_HASH]
         | 
| 68 | 
            +
            pp Fastlane::Actions.lane_context[Fastlane::Actions::ShatedValues::ANALYZE_IOS_LINKMAP_PARSED_MERGE_JSON]
         | 
| 40 69 | 
             
            ```
         | 
| 41 70 |  | 
| 71 | 
            +
            ### Eg5: 搜索一个 symbol 所属的 library
         | 
| 72 | 
            +
             | 
| 73 | 
            +
            ```ruby
         | 
| 74 | 
            +
            path = '/Users/xiongzenghui/Desktop/Demo-LinkMap-normal-arm64.txt'
         | 
| 75 | 
            +
            Fastlane::Actions::AnalyzeIosLinkmapAction.run(
         | 
| 76 | 
            +
              file_path: path,
         | 
| 77 | 
            +
              search_symbol: 'TDATEvo'
         | 
| 78 | 
            +
            )
         | 
| 79 | 
            +
            pp Fastlane::Actions.lane_context[Fastlane::Actions::ShatedValues::ANALYZE_IOS_LINKMAP_SEARCH_SYMBOL]
         | 
| 80 | 
            +
            ```
         | 
| 42 81 |  | 
| 43 82 |  | 
| 44 83 | 
             
            ## Run tests for this plugin
         | 
| @@ -1,62 +1,77 @@ | |
| 1 1 | 
             
            require 'fastlane/action'
         | 
| 2 | 
            -
            require_relative '../helper/ | 
| 2 | 
            +
            require_relative '../helper/analyze_ios_linkmap_parser'
         | 
| 3 3 |  | 
| 4 4 | 
             
            module Fastlane
         | 
| 5 5 | 
             
              module Actions
         | 
| 6 6 | 
             
                module ShatedValues
         | 
| 7 | 
            -
                  ANALYZE_IOS_LINKMAP_SEARCH_SYMBOL | 
| 8 | 
            -
                  ANALYZE_IOS_LINKMAP_PARSED_HASH | 
| 9 | 
            -
                  ANALYZE_IOS_LINKMAP_PARSED_JSON | 
| 7 | 
            +
                  ANALYZE_IOS_LINKMAP_SEARCH_SYMBOL     = :ANALYZE_IOS_LINKMAP_SEARCH_SYMBOL
         | 
| 8 | 
            +
                  ANALYZE_IOS_LINKMAP_PARSED_HASH       = :ANALYZE_IOS_LINKMAP_PARSED_HASH
         | 
| 9 | 
            +
                  ANALYZE_IOS_LINKMAP_PARSED_JSON       = :ANALYZE_IOS_LINKMAP_PARSED_JSON
         | 
| 10 10 | 
             
                  ANALYZE_IOS_LINKMAP_PARSED_MERGE_HASH = :ANALYZE_IOS_LINKMAP_PARSED_MERGE_HASH
         | 
| 11 11 | 
             
                  ANALYZE_IOS_LINKMAP_PARSED_MERGE_JSON = :ANALYZE_IOS_LINKMAP_PARSED_MERGE_JSON
         | 
| 12 12 | 
             
                end
         | 
| 13 13 |  | 
| 14 14 | 
             
                class AnalyzeIosLinkmapAction < Action
         | 
| 15 15 | 
             
                  def self.run(params)
         | 
| 16 | 
            -
                     | 
| 16 | 
            +
                    file_path     = params[:file_path]
         | 
| 17 17 | 
             
                    search_symbol = params[:search_symbol]
         | 
| 18 | 
            -
                     | 
| 19 | 
            -
                     | 
| 18 | 
            +
                    all_objects   = params[:all_objects]  || false
         | 
| 19 | 
            +
                    all_symbols   = params[:all_symbols]  || false
         | 
| 20 | 
            +
                    merge_by_pod  = params[:merge_by_pod] || false
         | 
| 20 21 |  | 
| 21 | 
            -
                     | 
| 22 | 
            -
                       | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 22 | 
            +
                    linkmap_parser = Fastlane::Helper::LinkMap::Parser.new(
         | 
| 23 | 
            +
                      if search_symbol
         | 
| 24 | 
            +
                        {
         | 
| 25 | 
            +
                          file_path: file_path,
         | 
| 26 | 
            +
                          all_objects: true,
         | 
| 27 | 
            +
                          all_symbols: true
         | 
| 28 | 
            +
                        }
         | 
| 29 | 
            +
                      else
         | 
| 30 | 
            +
                        {
         | 
| 31 | 
            +
                          file_path: file_path,
         | 
| 32 | 
            +
                          all_objects: all_objects,
         | 
| 33 | 
            +
                          all_symbols: all_symbols
         | 
| 34 | 
            +
                        }
         | 
| 35 | 
            +
                      end
         | 
| 36 | 
            +
                    )
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                    # parse Linkmap.txt
         | 
| 39 | 
            +
                    Fastlane::Actions.lane_context[Fastlane::Actions::ShatedValues::ANALYZE_IOS_LINKMAP_PARSED_HASH] = linkmap_parser.pretty_hash
         | 
| 40 | 
            +
                    Fastlane::Actions.lane_context[Fastlane::Actions::ShatedValues::ANALYZE_IOS_LINKMAP_PARSED_JSON] = linkmap_parser.pretty_json
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                    # merge Linkmap.txt parsed all symbols by library
         | 
| 43 | 
            +
                    if merge_by_pod
         | 
| 44 | 
            +
                      Fastlane::Actions.lane_context[Fastlane::Actions::ShatedValues::ANALYZE_IOS_LINKMAP_PARSED_MERGE_HASH] = linkmap_parser.pretty_merge_by_pod_hash
         | 
| 45 | 
            +
                      Fastlane::Actions.lane_context[Fastlane::Actions::ShatedValues::ANALYZE_IOS_LINKMAP_PARSED_MERGE_JSON] = linkmap_parser.pretty_merge_by_pod_json
         | 
| 46 | 
            +
                    end
         | 
| 25 47 |  | 
| 48 | 
            +
                    # if search a symbol from Linkmap.txt
         | 
| 26 49 | 
             
                    if search_symbol
         | 
| 27 50 | 
             
                      Fastlane::Actions.lane_context[Fastlane::Actions::ShatedValues::ANALYZE_IOS_LINKMAP_SEARCH_SYMBOL] = []
         | 
| 28 | 
            -
                       | 
| 29 | 
            -
                        lib[: | 
| 51 | 
            +
                      linkmap_parser.pretty_hash[:librarys].each do |lib|
         | 
| 52 | 
            +
                        lib[:object_files].each do |obj|
         | 
| 30 53 | 
             
                          obj[:symbols].each do |symol|
         | 
| 31 54 | 
             
                            next unless symol[:name].include?(search_symbol)
         | 
| 32 55 |  | 
| 33 56 | 
             
                            Fastlane::Actions.lane_context[Fastlane::Actions::ShatedValues::ANALYZE_IOS_LINKMAP_SEARCH_SYMBOL] << {
         | 
| 34 | 
            -
                              library: lib[: | 
| 35 | 
            -
                              object_file: obj[: | 
| 57 | 
            +
                              library: lib[:name],
         | 
| 58 | 
            +
                              object_file: obj[:file_name],
         | 
| 36 59 | 
             
                              symbol: symol[:name]
         | 
| 37 60 | 
             
                            }
         | 
| 38 61 | 
             
                          end
         | 
| 39 62 | 
             
                        end
         | 
| 40 63 | 
             
                      end
         | 
| 41 64 | 
             
                    end
         | 
| 42 | 
            -
             | 
| 43 | 
            -
                    Fastlane::Actions.lane_context[Fastlane::Actions::ShatedValues::ANALYZE_IOS_LINKMAP_PARSED_HASH] = parser.pretty_hash
         | 
| 44 | 
            -
                    Fastlane::Actions.lane_context[Fastlane::Actions::ShatedValues::ANALYZE_IOS_LINKMAP_PARSED_JSON] = parser.pretty_json
         | 
| 45 | 
            -
             | 
| 46 | 
            -
                    if merge_by_pod
         | 
| 47 | 
            -
                      Fastlane::Actions.lane_context[Fastlane::Actions::ShatedValues::ANALYZE_IOS_LINKMAP_PARSED_MERGE_HASH] = parser.pretty_merge_by_pod_hash
         | 
| 48 | 
            -
                      Fastlane::Actions.lane_context[Fastlane::Actions::ShatedValues::ANALYZE_IOS_LINKMAP_PARSED_MERGE_JSON] = parser.pretty_merge_by_pod_json
         | 
| 49 | 
            -
                    end
         | 
| 50 65 | 
             
                  end
         | 
| 51 66 |  | 
| 52 67 | 
             
                  def self.available_options
         | 
| 53 68 | 
             
                    [
         | 
| 54 69 | 
             
                      FastlaneCore::ConfigItem.new(
         | 
| 55 | 
            -
                        key: : | 
| 70 | 
            +
                        key: :file_path,
         | 
| 56 71 | 
             
                        description: "/your/path/to/linkmap.txt",
         | 
| 57 | 
            -
                        verify_block: ->(value) { | 
| 58 | 
            -
                          UI.user_error("❌  | 
| 59 | 
            -
                          UI.user_error!("❌  | 
| 72 | 
            +
                        verify_block: ->(value) {
         | 
| 73 | 
            +
                          UI.user_error("❌ file_path not pass") unless value
         | 
| 74 | 
            +
                          UI.user_error!("❌ file_path #{value} not exist") unless File.exist?(value)
         | 
| 60 75 | 
             
                        }
         | 
| 61 76 | 
             
                      ),
         | 
| 62 77 | 
             
                      FastlaneCore::ConfigItem.new(
         | 
| @@ -66,35 +81,29 @@ module Fastlane | |
| 66 81 | 
             
                      ),
         | 
| 67 82 | 
             
                      FastlaneCore::ConfigItem.new(
         | 
| 68 83 | 
             
                        key: :all_symbols,
         | 
| 69 | 
            -
                        description: "print all  | 
| 70 | 
            -
                        optional: true
         | 
| 84 | 
            +
                        description: "print a object fille all symbols ???",
         | 
| 85 | 
            +
                        optional: true,
         | 
| 86 | 
            +
                        default_value: false,
         | 
| 87 | 
            +
                        is_string: false
         | 
| 88 | 
            +
                      ),
         | 
| 89 | 
            +
                      FastlaneCore::ConfigItem.new(
         | 
| 90 | 
            +
                        key: :all_objects,
         | 
| 91 | 
            +
                        description: "print a library all object files ???",
         | 
| 92 | 
            +
                        optional: true,
         | 
| 93 | 
            +
                        default_value: false,
         | 
| 94 | 
            +
                        is_string: false
         | 
| 71 95 | 
             
                      ),
         | 
| 72 96 | 
             
                      FastlaneCore::ConfigItem.new(
         | 
| 73 97 | 
             
                        key: :merge_by_pod,
         | 
| 74 98 | 
             
                        description: "merge linkmap parsed hash by pod name ???",
         | 
| 75 | 
            -
                        optional: true
         | 
| 99 | 
            +
                        optional: true,
         | 
| 100 | 
            +
                        default_value: false,
         | 
| 101 | 
            +
                        is_string: false
         | 
| 76 102 | 
             
                      )
         | 
| 77 103 | 
             
                    ]
         | 
| 78 104 | 
             
                  end
         | 
| 79 105 |  | 
| 80 106 | 
             
                  def self.example_code
         | 
| 81 | 
            -
                    [
         | 
| 82 | 
            -
                      'analyze_ios_linkmap(filepath: "/path/to/linkmap.txt")
         | 
| 83 | 
            -
                      pp Fastlane::Actions.lane_context[Fastlane::Actions::ShatedValues::ANALYZE_IOS_LINKMAP_PARSED_HASH]
         | 
| 84 | 
            -
                      pp Fastlane::Actions.lane_context[Fastlane::Actions::ShatedValues::ANALYZE_IOS_LINKMAP_PARSED_JSON]',
         | 
| 85 | 
            -
                      'analyze_ios_linkmap(
         | 
| 86 | 
            -
                        filepath: "/path/to/linkmap.txt",
         | 
| 87 | 
            -
                        search_symbol: "TDATEvo"
         | 
| 88 | 
            -
                      )
         | 
| 89 | 
            -
                      pp Fastlane::Actions.lane_context[Fastlane::Actions::ShatedValues::ANALYZE_IOS_LINKMAP_SEARCH_SYMBOL]'
         | 
| 90 | 
            -
                      'analyze_ios_linkmap(
         | 
| 91 | 
            -
                        filepath: "/path/to/linkmap.txt",
         | 
| 92 | 
            -
                        all_symbols: false,
         | 
| 93 | 
            -
                        merge_by_pod: true
         | 
| 94 | 
            -
                      )
         | 
| 95 | 
            -
                      pp Fastlane::Actions.lane_context[Fastlane::Actions::ShatedValues::ANALYZE_IOS_LINKMAP_PARSED_MERGE_HASH]
         | 
| 96 | 
            -
                      pp Fastlane::Actions.lane_context[Fastlane::Actions::ShatedValues::ANALYZE_IOS_LINKMAP_PARSED_MERGE_JSON]'
         | 
| 97 | 
            -
                    ]
         | 
| 98 107 | 
             
                  end
         | 
| 99 108 |  | 
| 100 109 | 
             
                  def self.return_value
         | 
| @@ -0,0 +1,299 @@ | |
| 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 | 
            +
                  require 'json'
         | 
| 9 | 
            +
                  require_relative 'linkmap_helper'
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  class Parser
         | 
| 12 | 
            +
                    attr_accessor(:object_map, :library_map, :section_map, :segment_map)
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                    def initialize(options)
         | 
| 15 | 
            +
                      @file_path   = options[:file_path]
         | 
| 16 | 
            +
                      @all_objects = options[:all_objects] || false
         | 
| 17 | 
            +
                      @all_symbols = options[:all_symbols] || false
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                      unless @file_path
         | 
| 20 | 
            +
                        raise "❌ [Parser] file_path not pass"
         | 
| 21 | 
            +
                      end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                      unless File.exist?(@file_path)
         | 
| 24 | 
            +
                        raise "❌ [Parser] file at #{@file_path} not exist"
         | 
| 25 | 
            +
                      end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                      @object_map  = {}
         | 
| 28 | 
            +
                      @library_map = {}
         | 
| 29 | 
            +
                      @section_map = {}
         | 
| 30 | 
            +
                      @segment_map = {}
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                      parse
         | 
| 33 | 
            +
                    end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                    #
         | 
| 36 | 
            +
                    # 读取并解析 Linkmap.txt 文件的【每一行】内容
         | 
| 37 | 
            +
                    #
         | 
| 38 | 
            +
                    def parse
         | 
| 39 | 
            +
                      File.foreach(@file_path).with_index do |line, num|
         | 
| 40 | 
            +
                        # begin
         | 
| 41 | 
            +
                          unless line.valid_encoding?
         | 
| 42 | 
            +
                            line = line.encode("UTF-16", :invalid => :replace, :replace => "?").encode('UTF-8')
         | 
| 43 | 
            +
                          end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                          if line.start_with? "#"
         | 
| 46 | 
            +
                            if line.start_with? "# Object files:"
         | 
| 47 | 
            +
                              @subparser = :parse_object_files
         | 
| 48 | 
            +
                            elsif line.start_with? "# Sections:"
         | 
| 49 | 
            +
                              @subparser = :parse_sections
         | 
| 50 | 
            +
                            elsif line.start_with? "# Symbols:"
         | 
| 51 | 
            +
                              @subparser = :parse_symbols
         | 
| 52 | 
            +
                            elsif line.start_with? '# Dead Stripped Symbols:'
         | 
| 53 | 
            +
                              @subparser = :parse_dead_stripped_symbols
         | 
| 54 | 
            +
                            end
         | 
| 55 | 
            +
                          else
         | 
| 56 | 
            +
                            send(@subparser, line)
         | 
| 57 | 
            +
                          end
         | 
| 58 | 
            +
                        # rescue => e
         | 
| 59 | 
            +
                        #   UI.error "Exception on LinkMap file line #{num}:"
         | 
| 60 | 
            +
                        #   # UI.message line
         | 
| 61 | 
            +
                        # end
         | 
| 62 | 
            +
                      end
         | 
| 63 | 
            +
                      # puts "There are #{@section_map.values.map{|value| value[:residual_size]}.inject(:+)} Byte in some section can not be analyze"
         | 
| 64 | 
            +
                    end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                    def parse_object_files(line)
         | 
| 67 | 
            +
                      ObjectFile.new(line) do |of, type|
         | 
| 68 | 
            +
                        # 保存解析完成的 ObjectFile
         | 
| 69 | 
            +
                        @object_map[of.index] = of
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                        # xx.o 没有 Library 的情况
         | 
| 72 | 
            +
                        next if OBJECT_FILE_TYPE_SYSTEM == type #=> 1) system 类型的 xx.o 不创建 Library
         | 
| 73 | 
            +
                        next unless of.library                  #=> 2) xx.o 没有归属的 library
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                        # 创建/获取 xx.o 归属到的 library
         | 
| 76 | 
            +
                        library = @library_map[of.library]
         | 
| 77 | 
            +
                        library ||= Library.new({
         | 
| 78 | 
            +
                          name: of.library,
         | 
| 79 | 
            +
                          size: of.size,
         | 
| 80 | 
            +
                          object_files: Array.new,
         | 
| 81 | 
            +
                          dead_symbol_size: of.dead_symbol_size
         | 
| 82 | 
            +
                        })
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                        # 只有【用户】类型的【xx.a】和【xx.framework】, 才可能是 CocoaPods 方式集成, 也才会有 podspec name
         | 
| 85 | 
            +
                        # podspec、subspec
         | 
| 86 | 
            +
                        ## - 1) 没有 subspec
         | 
| 87 | 
            +
                        # /path/to/Pods/BaiduMobAdSDK/BaiduMobAdSDK/BaiduMobAdSDK.framework ==> podspec name: BaiduMobAdSDK
         | 
| 88 | 
            +
                        ## - 2) 有 subspec
         | 
| 89 | 
            +
                        # /path/to/Pods/AlibcSDK/AlibcSDK/Frameworks/UTDID/UTDID.framework  ==> podspec name: AlibcSDK, subspec name: UTDID
         | 
| 90 | 
            +
                        # /path/to/Pods/AlibcSDK/AlibcSDK/Frameworks/AliAuthSDK/AlibabaAuthExt.framework ==> podspec name: AlibcSDK, subspec name: AliAuthSDK
         | 
| 91 | 
            +
                        # /path/to/Pods/AlibcSDK/AlibcSDK/Frameworks/AliAuthSDK/AlibabaAuthSDK.framework ==> podspec name: AlibcSDK, subspec name: AliAuthSDK
         | 
| 92 | 
            +
                        #
         | 
| 93 | 
            +
                        # 结论
         | 
| 94 | 
            +
                        # - 1) /path/to/pods/<Podspec#name>/.../xx.framework 或 xx.a
         | 
| 95 | 
            +
                        # - 2) /path/to/pods/<Podspec#name>/.../<Subspec#name>/xx.framework 或 xx.a ==> <Subspec#name> 不好确定
         | 
| 96 | 
            +
                        #
         | 
| 97 | 
            +
                        if OBJECT_FILE_TYPE_USER_LIBRARY == type
         | 
| 98 | 
            +
                          if line.include?('/Pods/')
         | 
| 99 | 
            +
                            # [ 23] /path/to/App/Pods/AFNetworking/AFNetworking.framework/AFNetworking(AFAutoPurgingImageCache.o)
         | 
| 100 | 
            +
                            divstr = line.split('/Pods/').last      #=> AFNetworking/AFNetworking.framework/AFNetworking(AFAutoPurgingImageCache.o)
         | 
| 101 | 
            +
                            podspec_name = divstr.split('/').first  #=> AFNetworking
         | 
| 102 | 
            +
                            library.podspec_name = podspec_name
         | 
| 103 | 
            +
                          else
         | 
| 104 | 
            +
                            library.podspec_name = nil
         | 
| 105 | 
            +
                          end
         | 
| 106 | 
            +
                        end
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                        # library【追加】位于 `# Object Files` 后面【xx.o 目标文件】的 下标值 [ n]
         | 
| 109 | 
            +
                        library.object_files << of.index
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                        # 保存/更新 library
         | 
| 112 | 
            +
                        @library_map[of.library] = library
         | 
| 113 | 
            +
                      end
         | 
| 114 | 
            +
                    end
         | 
| 115 | 
            +
             | 
| 116 | 
            +
                    def parse_sections(line)
         | 
| 117 | 
            +
                      section                   = Section.new(line)
         | 
| 118 | 
            +
                      @section_map[section.key] = section
         | 
| 119 | 
            +
                    end
         | 
| 120 | 
            +
             | 
| 121 | 
            +
                    def parse_symbols(line)
         | 
| 122 | 
            +
                      symbol = Fastlane::Helper::LinkMap::Symbol.new(line)
         | 
| 123 | 
            +
                      return if symbol.invalid #=> line parse failed
         | 
| 124 | 
            +
             | 
| 125 | 
            +
                      object_file = @object_map[symbol.file]
         | 
| 126 | 
            +
                      return unless object_file #=> line can not found object file
         | 
| 127 | 
            +
             | 
| 128 | 
            +
                      # 累加1: 一个 ObjectFile 总大小 (包含 N个 Symbol)
         | 
| 129 | 
            +
                      object_file.add_symbol(symbol)
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                      # 累加2: 一个 Library 总大小 (包含 N个 ObjectFile)
         | 
| 132 | 
            +
                      library      =  @library_map[object_file.library]
         | 
| 133 | 
            +
                      library.size += symbol.size if library
         | 
| 134 | 
            +
             | 
| 135 | 
            +
                      # 累加3: 一个 Segment 总大小 (包含 N个 Section)
         | 
| 136 | 
            +
                      ## 找到 当前被解析 symbol 所属的 section
         | 
| 137 | 
            +
                      section = @section_map.detect do |_, sec|
         | 
| 138 | 
            +
                        if sec
         | 
| 139 | 
            +
                          (sec.start_addr...sec.end_addr).include?(symbol.address)
         | 
| 140 | 
            +
                        else
         | 
| 141 | 
            +
                          false
         | 
| 142 | 
            +
                        end
         | 
| 143 | 
            +
                      end #=> [:"__TEXT:__text", #<FastlaneCore::Helper::LinkMap::Section:0x00007fd8e3787eb8 ...>]
         | 
| 144 | 
            +
                      ## 再把 当前被解析 symbol 符号总大小, 累加到
         | 
| 145 | 
            +
                      if section
         | 
| 146 | 
            +
                        key          = section[0] #=> :"__TEXT:__text"
         | 
| 147 | 
            +
                        value        = section[1] #=> #<FastlaneCore::Helper::LinkMap::Section:0x00007fd8e3787eb8 ...>
         | 
| 148 | 
            +
             | 
| 149 | 
            +
                        segment_name = value.to_segment           #=> 解析出 section 所属的 segment name
         | 
| 150 | 
            +
                        segment      = @segment_map[segment_name] #=> 尝试从 segment map 中, 查找是否有 缓存的 segment 对象
         | 
| 151 | 
            +
             | 
| 152 | 
            +
                        unless segment
         | 
| 153 | 
            +
                          segment = Segment.new({ name: segment_name, size: symbol.size, residual_size: symbol.size })
         | 
| 154 | 
            +
                        else
         | 
| 155 | 
            +
                          segment.size          += symbol.size
         | 
| 156 | 
            +
                          segment.residual_size += symbol.size
         | 
| 157 | 
            +
                        end
         | 
| 158 | 
            +
             | 
| 159 | 
            +
                        @segment_map[segment_name] = segment
         | 
| 160 | 
            +
                      end
         | 
| 161 | 
            +
                    end
         | 
| 162 | 
            +
             | 
| 163 | 
            +
                    def parse_dead_stripped_symbols(line)
         | 
| 164 | 
            +
                      stripped_symbol = DeadStrippedSymbol.new(line)
         | 
| 165 | 
            +
                      return if stripped_symbol.invalid #=> line parse failed
         | 
| 166 | 
            +
             | 
| 167 | 
            +
                      object_file = @object_map[stripped_symbol.file]
         | 
| 168 | 
            +
                      return unless object_file #=> line can not found object file
         | 
| 169 | 
            +
             | 
| 170 | 
            +
                      # 累加 一个 ObjectFile 总大小 (包含 N个 Dead Stripped Symbol)
         | 
| 171 | 
            +
                      object_file.dead_symbol_size += stripped_symbol.size
         | 
| 172 | 
            +
             | 
| 173 | 
            +
                      # 累加 一个 Library 总大小 (包含 N个 ObjectFile)
         | 
| 174 | 
            +
                      library = @library_map[object_file.library]
         | 
| 175 | 
            +
                      return unless library
         | 
| 176 | 
            +
                      library.dead_symbol_size += stripped_symbol.size
         | 
| 177 | 
            +
                    end
         | 
| 178 | 
            +
             | 
| 179 | 
            +
                    def pretty_json
         | 
| 180 | 
            +
                      return @json_result if @json_result
         | 
| 181 | 
            +
             | 
| 182 | 
            +
                      @json_result = JSON.pretty_generate(pretty_hash)
         | 
| 183 | 
            +
                      @json_result
         | 
| 184 | 
            +
                    end
         | 
| 185 | 
            +
             | 
| 186 | 
            +
                    def pretty_hash
         | 
| 187 | 
            +
                      return @hash_result if @hash_result
         | 
| 188 | 
            +
             | 
| 189 | 
            +
                      # sort object_map[i].ObjectFile.symbols
         | 
| 190 | 
            +
                      @object_map.each do |_, object_file|
         | 
| 191 | 
            +
                        next unless object_file.symbols
         | 
| 192 | 
            +
             | 
| 193 | 
            +
                        object_file.symbols.sort! do |sym1, sym2|
         | 
| 194 | 
            +
                          sym2.size <=> sym1.size
         | 
| 195 | 
            +
                        end
         | 
| 196 | 
            +
                      end
         | 
| 197 | 
            +
             | 
| 198 | 
            +
                      # 计算 linkmap.txt 所有的 symbol 总大小
         | 
| 199 | 
            +
                      total_size = @library_map.values.map(&:size).inject(:+)
         | 
| 200 | 
            +
                      total_dead_size = @library_map.values.map(&:dead_symbol_size).inject(:+)
         | 
| 201 | 
            +
             | 
| 202 | 
            +
                      # sort library_map[i]
         | 
| 203 | 
            +
                      sorted_librarys = @library_map.values.sort do |a, b|
         | 
| 204 | 
            +
                        b.size <=> a.size
         | 
| 205 | 
            +
                      end
         | 
| 206 | 
            +
             | 
| 207 | 
            +
                      # fixed library_map[i].object_files[i]
         | 
| 208 | 
            +
                      fixed_librarys = sorted_librarys.map { |lib|
         | 
| 209 | 
            +
                        fixed_library = lib.to_hash(@all_objects)
         | 
| 210 | 
            +
             | 
| 211 | 
            +
                        if @all_objects
         | 
| 212 | 
            +
                          fixed_library[:object_files] = lib.object_files.map { |object_file_index|
         | 
| 213 | 
            +
                            # 修正 object file [1,2,3,...] ==> ["TXVodPlayerStatsCollection.o", "TXVodDownloadManager.o", "TXUGCVideoRecorder.o", ...]
         | 
| 214 | 
            +
                            object_file = object_map[object_file_index]
         | 
| 215 | 
            +
             | 
| 216 | 
            +
                            # fixed library_map[i].object_files[i].symbols 是否打印每一个 object file 下面 all symbol
         | 
| 217 | 
            +
                            if object_file
         | 
| 218 | 
            +
                              object_file.to_hash(@all_symbols)
         | 
| 219 | 
            +
                            else
         | 
| 220 | 
            +
                              nil
         | 
| 221 | 
            +
                            end
         | 
| 222 | 
            +
                          }.compact
         | 
| 223 | 
            +
                        end
         | 
| 224 | 
            +
             | 
| 225 | 
            +
                        fixed_library
         | 
| 226 | 
            +
                      }
         | 
| 227 | 
            +
             | 
| 228 | 
            +
                      @hash_result = {
         | 
| 229 | 
            +
                        count: fixed_librarys.count,
         | 
| 230 | 
            +
                        size: total_size,
         | 
| 231 | 
            +
                        format_total_size: Fastlane::Helper::LinkMap::FileHelper.format_size(total_size),
         | 
| 232 | 
            +
                        dead_size: total_dead_size,
         | 
| 233 | 
            +
                        format_dead_size: Fastlane::Helper::LinkMap::FileHelper.format_size(total_dead_size),
         | 
| 234 | 
            +
                        librarys: fixed_librarys
         | 
| 235 | 
            +
                      }
         | 
| 236 | 
            +
                      @hash_result
         | 
| 237 | 
            +
                    end
         | 
| 238 | 
            +
             | 
| 239 | 
            +
                    def pretty_merge_by_pod_json
         | 
| 240 | 
            +
                      return @merge_json_result if @merge_json_result
         | 
| 241 | 
            +
                      @merge_json_result = JSON.pretty_generate(pretty_merge_by_pod_hash)
         | 
| 242 | 
            +
                      @merge_json_result
         | 
| 243 | 
            +
                    end
         | 
| 244 | 
            +
             | 
| 245 | 
            +
                    def pretty_merge_by_pod_hash
         | 
| 246 | 
            +
                      return @merge_hash_result if @merge_hash_result
         | 
| 247 | 
            +
             | 
| 248 | 
            +
                      @merge_hash_result = {
         | 
| 249 | 
            +
                        count: pretty_hash[:count],
         | 
| 250 | 
            +
                        size: pretty_hash[:size],
         | 
| 251 | 
            +
                        format_size: pretty_hash[:format_size],
         | 
| 252 | 
            +
                        dead_size: pretty_hash[:dead_size],
         | 
| 253 | 
            +
                        format_dead_size: pretty_hash[:format_dead_size]
         | 
| 254 | 
            +
                      }
         | 
| 255 | 
            +
             | 
| 256 | 
            +
                      # 合并 subspec 下的 library
         | 
| 257 | 
            +
                      # AlibcSDK.podspec
         | 
| 258 | 
            +
                      # ------------------------------------------------------------------
         | 
| 259 | 
            +
                      # $ cd /path/to/App/Pods/AlibcSDK/AlibcSDK/Frameworks
         | 
| 260 | 
            +
                      # $ tree -d -L 3
         | 
| 261 | 
            +
                      # .
         | 
| 262 | 
            +
                      # ├── AliAuthSDK
         | 
| 263 | 
            +
                      # │   ├── AlibabaAuthExt.framework
         | 
| 264 | 
            +
                      # │   └── AlibabaAuthSDK.framework
         | 
| 265 | 
            +
                      # ├── AliLinkPartnerSDK
         | 
| 266 | 
            +
                      # │   └── AlibcLinkPartnerSDK.framework
         | 
| 267 | 
            +
                      # ├── AlibcTradeSDK
         | 
| 268 | 
            +
                      # │   ├── AlibcTradeBiz.framework
         | 
| 269 | 
            +
                      # │   └── AlibcTradeSDK.framework
         | 
| 270 | 
            +
                      # ├── BCUserTrack
         | 
| 271 | 
            +
                      # │   └── UTMini.framework
         | 
| 272 | 
            +
                      # ├── UTDID
         | 
| 273 | 
            +
                      # │   └── UTDID.framework
         | 
| 274 | 
            +
                      # ├── mtopSDK
         | 
| 275 | 
            +
                      # │   ├── MtopSDK.framework
         | 
| 276 | 
            +
                      # │   ├── mtopcoreopen.framework
         | 
| 277 | 
            +
                      # │   └── mtopext.framework
         | 
| 278 | 
            +
                      # └── securityGuard
         | 
| 279 | 
            +
                      #     ├── SGAVMP.framework
         | 
| 280 | 
            +
                      #     ├── SGMain.framework
         | 
| 281 | 
            +
                      #     ├── SGMiddleTier.framework
         | 
| 282 | 
            +
                      #     ├── SGSecurityBody.framework
         | 
| 283 | 
            +
                      #     └── SecurityGuardSDK.framework
         | 
| 284 | 
            +
                      #
         | 
| 285 | 
            +
                      pod_hash = Hash.new
         | 
| 286 | 
            +
                      pretty_hash[:librarys].each_with_object(pod_hash) do |lib, hash|
         | 
| 287 | 
            +
                        apod_librarys = hash[lib[:podspec_name]]
         | 
| 288 | 
            +
                        apod_librarys ||= Array.new
         | 
| 289 | 
            +
                        apod_librarys << lib
         | 
| 290 | 
            +
                        hash[lib[:podspec_name]] = apod_librarys
         | 
| 291 | 
            +
                      end
         | 
| 292 | 
            +
             | 
| 293 | 
            +
                      @merge_hash_result[:pods] = pod_hash
         | 
| 294 | 
            +
                      @merge_hash_result
         | 
| 295 | 
            +
                    end
         | 
| 296 | 
            +
                  end
         | 
| 297 | 
            +
                end
         | 
| 298 | 
            +
              end
         | 
| 299 | 
            +
            end
         |