cocoapods-hmap-prebuilt 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 06ec400c0386357e5211eebf6b5a14f9698e652c2f02349d393652b079528f35
4
+ data.tar.gz: 1e8b99f1e32e4086a24300566d0bcadb7b5395dfc19d58bf516878c80f50d68b
5
+ SHA512:
6
+ metadata.gz: 4bd94eb184b1f0c5d0fe2234001bdea13f38a31c3acea71d98b9a70e01cdf737fddc2f47118e42092846c84ffabdc3c03125576eb521e499e40fadd6ae164f83
7
+ data.tar.gz: 96017f250188e500d55cb8258885db82fd779b26643fafbb039c7592a7635275040bc99c3149deb54fae7f633df4f5b791cfd48f8c35540786a9ddba2bd4ce52
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2021 EricLou <499304609@qq.com>
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,40 @@
1
+ # cocoapods-hmap-prebuilt
2
+
3
+ A description of cocoapods-hmap-prebuilt.
4
+
5
+ ## Installation
6
+
7
+ $ gem install cocoapods-hmap-prebuilt
8
+
9
+ ## Usage
10
+
11
+ The command should be executed in directory that contains podfile.
12
+
13
+ ```shell
14
+ # write the hmap file to podfile/Pods/Headers/HMap
15
+ $ pod hmap-writer
16
+
17
+ # write the hmap file to /project/dir/Pods/Headers/HMap
18
+ $ pod hmap-writer --project-directory=/project/dir/
19
+
20
+ # write the hmap file to /project/dir/Pods/Headers/HMap and no save origin [HEADER_SEARCH_PATHS]
21
+ $ pod hmap-writer --project-directory=/project/dir/ --nosave-origin-header-search-paths
22
+
23
+ # cleanup the hmap file
24
+ $ pod hmap-writer --clean-hmap
25
+
26
+ # read the hmap file from /hmap/dir/file
27
+ $ pod hmap-reader --hmap-path=/hmap/dir/file
28
+ ```
29
+
30
+ At same time, you can put this line in your podfile:
31
+
32
+ ```rb
33
+ plugin 'cocoapods-hmap-prebuilt'
34
+ ```
35
+
36
+ ## Command Line Tool
37
+
38
+ Installing the 'cocoapods-hmap-prebuilt' gem will also install two command-line tool `hmap-prebuilt-read` and `hmap-prebuilt-write` which you can use to generate header map file and read hmap file.
39
+
40
+ For more information consult `hmap-prebuilt-read --help` or `hmap-prebuilt-write --help`.
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ if $PROGRAM_NAME == __FILE__
4
+ ENV['BUNDLE_GEMFILE'] = File.expand_path('../Gemfile', __dir__)
5
+ require 'bundler/setup'
6
+ end
7
+
8
+ require 'cocoapods-hmap-prebuilt/command/hmap_reader'
9
+
10
+ Pod::Command::HMapReader.run(ARGV)
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ if $PROGRAM_NAME == __FILE__
4
+ ENV['BUNDLE_GEMFILE'] = File.expand_path('../Gemfile', __dir__)
5
+ require 'bundler/setup'
6
+ end
7
+
8
+ require 'cocoapods-hmap-prebuilt/command/hmap_writer'
9
+
10
+ Pod::Command::HMapWriter.run(ARGV)
@@ -0,0 +1,13 @@
1
+ # The primary namespace for cocoapods-hmap-prebuilt.
2
+ module HMap
3
+ require_relative 'cocoapods-hmap-prebuilt/hmap_version'
4
+ require_relative 'cocoapods-hmap-prebuilt/hmap_view'
5
+ require_relative 'cocoapods-hmap-prebuilt/hmap_struct'
6
+ require_relative 'cocoapods-hmap-prebuilt/hmap_utils'
7
+ require_relative 'cocoapods-hmap-prebuilt/hmap_helper'
8
+ require_relative 'cocoapods-hmap-prebuilt/hmap_exceptions'
9
+
10
+ autoload :HMapFileReader, 'cocoapods-hmap-prebuilt/hmap_file_reader'
11
+ autoload :HMapFileWriter, 'cocoapods-hmap-prebuilt/hmap_file_writer'
12
+ autoload :HMapFile, 'cocoapods-hmap-prebuilt/hmap_file'
13
+ end
@@ -0,0 +1,39 @@
1
+ require 'cocoapods-hmap-prebuilt'
2
+ require 'cocoapods'
3
+
4
+ module Pod
5
+ class Command
6
+ class HMapReader < Command
7
+ self.summary = 'Read mapfile and puts result.'
8
+
9
+ self.description = <<-DESC
10
+ Read mapfile and puts result, header, buckets, string_table.
11
+ DESC
12
+
13
+ def initialize(argv)
14
+ super
15
+ hmap_file_path = argv.option('hmap-path')
16
+ @hmap_file_path = Pathname.new(hmap_file_path).expand_path unless hmap_file_path.nil?
17
+ end
18
+
19
+ def validate!
20
+ super
21
+ banner! if help?
22
+ raise '[ERROR]: --hmap-path no set'.red unless File.exist?(@hmap_file_path)
23
+ end
24
+
25
+ def self.options
26
+ [
27
+ ['--hmap-path=/hmap/dir/file', 'The path of the hmap file']
28
+ ].concat(super)
29
+ end
30
+
31
+ def run
32
+ UI.section "\n[hmap-reader] start..............\n".yellow do
33
+ HMap::MapFileReader.new(@hmap_file_path)
34
+ end
35
+ UI.puts("\n[hmap-reader] finish..............\n".yellow)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,46 @@
1
+ require 'cocoapods-hmap-prebuilt'
2
+ require 'cocoapods'
3
+
4
+ module Pod
5
+ class Command
6
+ class HMapWriter < Command
7
+ self.summary = 'Analyzes the dependencies and gen each dependencie mapfile.'
8
+
9
+ self.description = <<-DESC
10
+ Analyzes the dependencies of any cocoapods projects and gen each dependencie mapfile.
11
+ DESC
12
+
13
+ def initialize(argv)
14
+ super
15
+ project_directory = argv.option('project-directory')
16
+ @save_origin_header_search_paths = !argv.flag?('nosave-origin-header-search-paths', false)
17
+ @clean_hmap = argv.flag?('clean-hmap', false)
18
+
19
+ return if project_directory.nil?
20
+
21
+ @project_directory = Pathname.new(project_directory).expand_path
22
+ config.installation_root = @project_directory
23
+ end
24
+
25
+ def validate!
26
+ super
27
+ verify_podfile_exists!
28
+ end
29
+
30
+ def self.options
31
+ [
32
+ ['--project-directory=/project/dir/', 'The path to the root of the project directory'],
33
+ ['--nosave-origin-header-search-paths', 'This option will not save xcconfig origin [HEADER_SEARCH_PATHS] and put hmap file first'],
34
+ ['--clean-hmap', 'This option will clean up all hmap-prebuilt setup for hmap.']
35
+ ].concat(super)
36
+ end
37
+
38
+ def run
39
+ UI.section "\n[hmap-prebuilt] start.............." do
40
+ HMap::HMapFileWriter.new(@save_origin_header_search_paths, @clean_hmap)
41
+ end
42
+ UI.puts('[hmap-prebuilt] finish..............')
43
+ end
44
+ end
45
+ end
46
+ end
File without changes
File without changes
@@ -0,0 +1,91 @@
1
+ module HMap
2
+
3
+ class HMapFileReader
4
+ # @return [String, nil] the filename loaded from, or nil if loaded from a binary
5
+ # string
6
+ attr_reader :filename
7
+ # # @return [Hash] any parser options that the instance was created with
8
+ # attr_reader :options
9
+
10
+ # @return true/false the swapped of the mapfile
11
+ attr_reader :swapped
12
+
13
+ # @return [HMap::HMapHeader]
14
+ attr_reader :header
15
+
16
+ # @return [Hash<HMap::HMapBucket => HMap::HMapBucketStr>] an array of the file's bucktes
17
+ # @note bucktes are provided in order of ascending offset.
18
+ attr_reader :bucktes
19
+
20
+ def initialize(path)
21
+ raise ArgumentError, "#{path}: no such file" unless File.file?(path)
22
+
23
+ @filename = path
24
+ @raw_data = File.open(@filename, 'rb', &:read)
25
+ populate_fields
26
+ puts description
27
+ end
28
+
29
+ # Populate the instance's fields with the raw HMap data.
30
+ # @return [void]
31
+ # @note This method is public, but should (almost) never need to be called.
32
+ def populate_fields
33
+ @header = populate_hmap_header
34
+ string_t = @raw_data[header.strings_offset..-1]
35
+ @bucktes = populate_buckets do |bucket|
36
+ bucket_s = bucket.to_a.map do |key|
37
+ string_t[key..-1].match(/[^\0]+/)[0]
38
+ end
39
+ HMapBucketStr.new(*bucket_s)
40
+ end
41
+ end
42
+
43
+ # The file's HMapheader structure.
44
+ # @return [HMap::HMapHeader]
45
+ # @raise [TruncatedFileError] if the file is too small to have a valid header
46
+ # @api private
47
+ def populate_hmap_header
48
+ raise TruncatedFileError if @raw_data.size < HMapHeader.bytesize + 8 * HMapBucket.bytesize
49
+
50
+ populate_and_check_magic
51
+ HMapHeader.new_from_bin(swapped, @raw_data[0, HMapHeader.bytesize])
52
+ end
53
+
54
+ # Read just the file's magic number and check its validity.
55
+ # @return [Integer] the magic
56
+ # @raise [MagicError] if the magic is not valid HMap magic
57
+ # @api private
58
+ def populate_and_check_magic
59
+ magic = @raw_data[0..3].unpack1('N')
60
+ raise MagicError, magic unless Utils.magic?(magic)
61
+
62
+ version = @raw_data[4..5].unpack1('n')
63
+ @swapped = Utils.swapped_magic?(magic, version)
64
+ end
65
+
66
+ # All buckets in the file.
67
+ # @return [Array<HMap::HMapBucket>] an array of buckets
68
+ # @api private
69
+ def populate_buckets
70
+ bucket_offset = header.class.bytesize
71
+ bucktes = []
72
+ header.num_buckets.times do |i|
73
+ bucket = HMapBucket.new_from_bin(swapped, @raw_data[bucket_offset, HMapBucket.bytesize])
74
+ bucket_offset += HMapBucket.bytesize
75
+ next if bucket.key == HEADER_CONST[:HMAP_EMPTY_BUCKT_KEY]
76
+
77
+ bucktes[i] = { bucket => yield(bucket) }
78
+ end
79
+ bucktes
80
+ end
81
+
82
+ def description
83
+ sum = " Header map: #{filename}\n" + header.description
84
+ bucktes.each_with_index do |buckte_h, index|
85
+ sum += "\t- Bucket: #{index}" + Utils.safe_encode(buckte_h.values[0].description, 'UTF-8') unless buckte_h.nil?
86
+ sum
87
+ end
88
+ sum
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,148 @@
1
+ require 'cocoapods'
2
+
3
+ module HMap
4
+
5
+ HMAP_DIR_NAME = 'HMap'
6
+
7
+ # mapfile type
8
+ # @note public => pods public,
9
+ # private => pods private,
10
+ # all => public + private + extra.
11
+ # @api private
12
+ HMMAP_TYPE = {
13
+ public_header_files: 'public',
14
+ private_header_files: 'private',
15
+ all_files: 'all'
16
+ }.freeze
17
+
18
+ HEAD_SEARCH_PATHS = 'HEADER_SEARCH_PATHS'
19
+
20
+ # Helper module which returns handle method from HMapFileWriter.
21
+ class HMapFileWriter
22
+ def initialize(save_origin_header_search_paths, clean_hmap)
23
+ config = Pod::Config.instance
24
+ analyze = Helper::PodHelper.pod_analyze(config)
25
+ hmap_dir = hmap_dir(config)
26
+ targets = analyze.targets
27
+ pod_targets = analyze.pod_targets
28
+ clean_hmap(clean_hmap, hmap_dir, targets, pod_targets)
29
+ return if clean_hmap
30
+
31
+ @save_origin_header_search_paths = save_origin_header_search_paths
32
+ gen_hmapfile(targets, pod_targets, hmap_dir)
33
+ end
34
+
35
+ private
36
+
37
+ def hmap_dir(config)
38
+ hmap_dir = File.join(config.sandbox.headers_root, HMAP_DIR_NAME)
39
+ puts "HMap dir: #{hmap_dir}"
40
+ hmap_dir
41
+ end
42
+
43
+ def clean_hmap(clean_hmap, hmap_dir, *targets)
44
+ return unless clean_hmap
45
+ FileUtils.rm_rf(hmap_dir)
46
+ targets.each do |tg|
47
+ Utils.clean_target_build_setting(tg, HEAD_SEARCH_PATHS)
48
+ end
49
+ end
50
+
51
+ def gen_hmapfile(targets, pod_targets, hmap_dir)
52
+ puts('Inspecting targets to integrate ')
53
+ merge_all_pods_target_headers_mapfile(pod_targets, hmap_dir)
54
+ merge_all_target_public_mapfile(targets, hmap_dir)
55
+ create_each_target_mapfile(pod_targets, hmap_dir)
56
+ end
57
+
58
+ def header_perfix(file, keys)
59
+ perfix = "#{file.dirname}/"
60
+ suffix = file.basename.to_s
61
+ keys.inject([]) do |sum, name|
62
+ sum << [name.to_s, perfix, suffix]
63
+ end
64
+ end
65
+
66
+ def header_to_hash(keys, headers, index, buckets)
67
+ index = index.length
68
+ keys.inject('') do |sum, bucket|
69
+ buckte = HMapBucketStr.new(*bucket)
70
+ string_t = buckte.bucket_to_string(headers, index + sum.length)
71
+ buckets.push(buckte)
72
+ sum + string_t
73
+ end
74
+ end
75
+
76
+ def merge_all_target_public_mapfile(targets, hmap_dir)
77
+ method = method(:from_header_mappings_by_file_accessor)
78
+ targets.each do |target|
79
+ hmap_file_name = "#{target.name}-All-Public-Headers.hmap"
80
+ single_target_mapfile(target.pod_targets, hmap_dir, hmap_file_name, method)
81
+ change_target_xcconfig_header_search_path([hmap_file_name], true, target)
82
+ end
83
+ end
84
+
85
+ def merge_all_pods_target_headers_mapfile(pod_targets, hmap_dir)
86
+ method = method(:from_header_mappings_by_file_accessor)
87
+ hmap_file_name = 'All-Pods-Headers.hmap'
88
+ single_target_mapfile(pod_targets, hmap_dir, hmap_file_name, method, :all_files)
89
+ change_target_xcconfig_header_search_path([hmap_file_name], false, *pod_targets)
90
+ end
91
+
92
+ def create_each_target_mapfile(pod_targets, hmap_dir)
93
+ pod_targets.each do |target|
94
+ HMMAP_TYPE.flat_map do |key, value|
95
+ hmap_file_name = "#{target.name}-#{value}-hmap.hmap"
96
+ method = method(:from_header_mappings_by_file_accessor)
97
+ single_target_mapfile([target], File.join(hmap_dir, target.name), hmap_file_name, method, key)
98
+ "#{target.name}/#{hmap_file_name}" if key == :all_files
99
+ end.compact
100
+ end
101
+ end
102
+
103
+ def from_header_mappings_by_file_accessor(header_h, buckets, target, hmap_type)
104
+ hmap_t = hmap_type == :all_files ? 'headers' : "#{HMMAP_TYPE[hmap_type]}_headers"
105
+ valid_accessors = target.file_accessors.reject { |fa| fa.spec.non_library_specification? }
106
+ headers = valid_accessors.each_with_object({}) do |file_accessor, sum|
107
+ # Private headers will always end up in Pods/Headers/Private/PodA/*.h
108
+ # This will allow for `""` imports to work.
109
+ type_header = file_accessor.method(hmap_t.to_sym).call
110
+ Helper::PodHelper.header_mappings(file_accessor, type_header, target).each do |key, value|
111
+ sum[key] ||= []
112
+ sum[key] += value
113
+ end
114
+ end
115
+
116
+ if target.build_as_framework?
117
+ headers[target.prefix_header_path] = [target.prefix_header_path.basename]
118
+ headers[target.umbrella_header_path] = [target.umbrella_header_path.basename]
119
+ end
120
+ headers.each_with_object(buckets) do |header_f, sum|
121
+ keys = header_perfix(*header_f)
122
+ sum[0] += header_to_hash(keys, header_h, *sum)
123
+ end
124
+ end
125
+
126
+ def single_target_mapfile(pod_targets, hmap_dir, hmap_file_name, headers, hmap_type = :public_header_files)
127
+ hmap_file_path = Pathname(File.join(hmap_dir, hmap_file_name))
128
+ header_h = {}
129
+ buckets = pod_targets.inject(["\0", []]) do |bucktes, target|
130
+ headers.call(header_h, bucktes, target, hmap_type)
131
+ end
132
+ wirte_mapfile_to_path(hmap_file_path, buckets)
133
+ end
134
+
135
+ def wirte_mapfile_to_path(hmap_file_path, buckets)
136
+ print "\t - save hmap file to path:"
137
+ puts hmap_file_path.to_s.yellow
138
+ HMapFile.new(*buckets).write(hmap_file_path)
139
+ end
140
+
141
+ def change_target_xcconfig_header_search_path(hmap_h, use_headermap, *targets)
142
+ Utils.target_xcconfig_path(targets) do |xc|
143
+ Utils.change_xcconfig_header_search_path(xc, hmap_h, use_headermap: use_headermap,
144
+ save_origin: @save_origin_header_search_paths)
145
+ end
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,85 @@
1
+
2
+ require 'cocoapods'
3
+
4
+ module HMap
5
+ # A collection of Helper functions used throughout cocoapods-hmap-prebuilt.
6
+ module Helper
7
+ # A collection of PodHelper functions used throughout cocoapods-hmap-prebuilt.
8
+ module PodHelper
9
+ HEADER_EXTENSIONS = Pod::Sandbox::FileAccessor::HEADER_EXTENSIONS
10
+
11
+ def self.pod_analyze(config)
12
+ podfile = Pod::Podfile.from_file(config.podfile_path)
13
+ lockfile = Pod::Lockfile.from_file(config.lockfile_path)
14
+ Pod::Installer::Analyzer.new(config.sandbox, podfile, lockfile).analyze
15
+ end
16
+
17
+ # @!group Private helpers
18
+
19
+ # Returns the list of the paths founds in the file system for the
20
+ # attribute with given name. It takes into account any dir pattern and
21
+ # any file excluded in the specification.
22
+ #
23
+ # @param [Symbol] attribute
24
+ # the name of the attribute.
25
+ #
26
+ # @return [Array<Pathname>] the paths.
27
+ #
28
+ def self.paths_for_attribute(key, attribute, include_dirs: false)
29
+ file_patterns = key.spec_consumer.send(attribute)
30
+ options = {
31
+ exclude_patterns: key.spec_consumer.exclude_files,
32
+ dir_pattern: Pod::Sandbox::FileAccessor::GLOB_PATTERNS[attribute],
33
+ include_dirs: include_dirs
34
+ }
35
+ extensions = HEADER_EXTENSIONS
36
+ key.path_list.relative_glob(file_patterns, options).map do |f|
37
+ [f, key.path_list.root.join(f)] if extensions.include?(f.extname)
38
+ end.compact
39
+ end
40
+
41
+ def self.header_mappings(file_accessor, headers, target)
42
+ consumer = file_accessor.spec_consumer
43
+ header_mappings_dir = consumer.header_mappings_dir
44
+ dir = target.headers_sandbox
45
+ dir_h = Pathname.new(target.product_module_name)
46
+ dir += consumer.header_dir if consumer.header_dir
47
+ mappings = {}
48
+ headers.each do |header|
49
+ next if header.to_s.include?('.framework/')
50
+
51
+ sub_dir = [dir, dir_h]
52
+ if header_mappings_dir
53
+ relative_path = header.relative_path_from(file_accessor.path_list.root + header_mappings_dir)
54
+ sub_dir << dir + relative_path.dirname
55
+ sub_dir << dir_h + relative_path.dirname
56
+ else
57
+ relative_path = header.relative_path_from(file_accessor.path_list.root)
58
+ sub_dir << relative_path.dirname
59
+ end
60
+ mappings[header] ||= []
61
+ sub_dir.uniq.each do |d|
62
+ mappings[header] << d + header.basename
63
+ end
64
+ mappings[header] << header.basename
65
+ end
66
+ mappings
67
+ end
68
+
69
+ def self.pod_target_source_header(target, hmap_t)
70
+ target.header_mappings_by_file_accessor.keys.flat_map do |key|
71
+ paths_for_attribute(key, hmap_t)
72
+ end
73
+ end
74
+
75
+ def self.pod_target_source_header_map(target, hmap_t)
76
+ pod_target_source_header(target, hmap_t).each_with_object({}) do |f, sum|
77
+ file = f[1]
78
+ key = f[0].to_s
79
+ r_key = file.basename.to_s
80
+ sum[r_key] = [key, r_key].uniq
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,264 @@
1
+
2
+ module HMap
3
+ HEADER_CONST = {
4
+ HMAP_HEADER_MAGIC_NUMBER: 0x686d6170,
5
+ HMAP_HEADER_VERSION: 0x0001,
6
+ HMAP_EMPTY_BUCKT_KEY: 0,
7
+ HMAP_SWAPPED_MAGIC: 0x70616d68,
8
+ HMAP_SWAPPED_VERSION: 0x0100
9
+ }.freeze
10
+
11
+ # A general purpose pseudo-structure.
12
+ # @abstract
13
+ class HMapStructure
14
+ # The String#unpack format of the data structure.
15
+ # @return [String] the unpacking format
16
+ # @api private
17
+ FORMAT = ''
18
+
19
+ # The size of the data structure, in bytes.
20
+ # @return [Integer] the size, in bytes
21
+ # @api private
22
+ SIZEOF = 0
23
+
24
+ SWAPPED = true
25
+
26
+ # @return [Integer] the size, in bytes, of the represented structure.
27
+ def self.bytesize
28
+ self::SIZEOF
29
+ end
30
+
31
+ def self.format
32
+ self::FORMAT
33
+ end
34
+
35
+ def self.swapped?
36
+ self::SWAPPED
37
+ end
38
+
39
+ # @param swapped [Bool] the swapped of the mapfile
40
+ # @param bin [String] the string to be unpacked into the new structure
41
+ # @return [HMap::HMapStructure] the resulting structure
42
+ # @api private
43
+ def self.new_from_bin(swapped, bin)
44
+ format = Utils.specialize_format(self::FORMAT, swapped)
45
+ new(*bin.unpack(format))
46
+ end
47
+
48
+ def serialize
49
+ [].pack(format)
50
+ end
51
+
52
+ # @return [Hash] a hash representation of this {HMapStructure}.
53
+ def to_h
54
+ {
55
+ 'structure' => {
56
+ 'format' => self.class::FORMAT,
57
+ 'bytesize' => self.class.bytesize
58
+ }
59
+ }
60
+ end
61
+ end
62
+
63
+ # HMapHeader structure.
64
+ # @see https://clang.llvm.org/doxygen/structclang_1_1HMapHeader.html
65
+ # @abstract
66
+ class HMapHeader < HMapStructure
67
+ # @return [HMap::HMapView, nil] the raw view associated with the load command,
68
+ # or nil if the HMapHeader was created via {create}.
69
+ attr_reader :num_entries, :magic, :version, :reserved, :strings_offset, :num_buckets, :max_value_length
70
+
71
+ FORMAT = 'L=1S=2L4'
72
+ # @see HMapStructure::SIZEOF
73
+ # @api private
74
+ SIZEOF = 24
75
+
76
+ # @api private
77
+ def initialize(magic, version, reserved, strings_offset, num_entries, num_buckets, max_value_length)
78
+ @magic = magic
79
+ @version = version
80
+ @reserved = reserved
81
+ @strings_offset = strings_offset
82
+ @num_entries = num_entries
83
+ @num_buckets = num_buckets
84
+ @max_value_length = max_value_length
85
+ super()
86
+ end
87
+
88
+ # @return [String] the serialized fields of the mafile
89
+ def serialize
90
+ format = Utils.specialize_format(FORMAT, SWAPPED)
91
+ [magic, version, reserved, strings_offset, num_entries, num_buckets, max_value_length].pack(format)
92
+ end
93
+
94
+ def description
95
+ <<-DESC
96
+ Hash bucket count: #{@num_buckets}
97
+ String table entry count: #{@num_entries}
98
+ Max value length: #{@max_value_length}
99
+ DESC
100
+ end
101
+
102
+ def to_h
103
+ {
104
+ 'magic' => magic,
105
+ 'version' => version,
106
+ 'reserved' => reserved,
107
+ 'strings_offset' => strings_offset,
108
+ 'num_entries' => num_entries,
109
+ 'num_buckets' => num_buckets,
110
+ 'max_value_length' => max_value_length
111
+ }.merge super
112
+ end
113
+ end
114
+
115
+ # HMapBucketStr => HMapBucket.
116
+ # @see https://clang.llvm.org/doxygen/structclang_1_1HMapHeader.html
117
+ # @abstract
118
+ class HMapBucketStr
119
+ attr_reader :uuid, :key, :perfix, :suffix
120
+
121
+ def initialize(key, perfix, suffix)
122
+ @uuid = Utils.string_downcase_hash(key)
123
+ @key = key
124
+ @perfix = perfix
125
+ @suffix = suffix
126
+ @str_ins = {}
127
+ end
128
+
129
+ def bucket_to_string(headers, index)
130
+ bucket = [key, perfix, suffix]
131
+ bucket.inject('') do |sum, arg|
132
+ if headers[arg].nil?
133
+ headers[arg] = sum.length + index
134
+ sum += "#{Utils.safe_encode(arg, 'ASCII-8BIT')}\0"
135
+ end
136
+ @str_ins[arg] = headers[arg]
137
+ sum
138
+ end
139
+ end
140
+
141
+ def bucket
142
+ HMapBucket.new(@str_ins[@key], @str_ins[@perfix], @str_ins[@suffix])
143
+ end
144
+
145
+ # @return [String] the serialized fields of the mafile
146
+ def serialize
147
+ bucket.serialize
148
+ end
149
+
150
+ def description
151
+ <<-DESC
152
+ Key #{@key} -> Prefix #{@perfix}, Suffix #{@suffix}
153
+ DESC
154
+ end
155
+
156
+ def to_h
157
+ {
158
+ 'key' => { 'index' => str_ins[@key], 'key' => @key },
159
+ 'perfix' => { 'index' => str_ins[@perfix], 'perfix' => @perfix },
160
+ 'suffix' => { 'index' => str_ins[@suffix], 'suffix' => @suffix }
161
+ }
162
+ end
163
+ end
164
+
165
+ # HMapBucket structure.
166
+ # @see https://clang.llvm.org/doxygen/structclang_1_1HMapHeader.html
167
+ # @abstract
168
+ class HMapBucket < HMapStructure
169
+ attr_accessor :key, :perfix, :suffix
170
+
171
+ SIZEOF = 12
172
+
173
+ FORMAT = 'L=3'
174
+
175
+ def initialize(key, perfix, suffix)
176
+ @key = key
177
+ @perfix = perfix
178
+ @suffix = suffix
179
+ super()
180
+ end
181
+
182
+ # @return [String] the serialized fields of the mafile
183
+ def serialize
184
+ format = Utils.specialize_format(FORMAT, SWAPPED)
185
+ [key, perfix, suffix].pack(format)
186
+ end
187
+
188
+ def to_a
189
+ [key, perfix, suffix]
190
+ end
191
+
192
+ def to_h
193
+ {
194
+ 'key' => key,
195
+ 'perfix' => perfix,
196
+ 'suffix' => suffix
197
+ }.merge super
198
+ end
199
+ end
200
+
201
+ # HMap blobs.
202
+ class HMapData
203
+ def initialize(buckets)
204
+ super()
205
+ count = buckets.count
206
+ nums = num_buckets(count, Utils.next_power_of_two(count))
207
+ entries = entries(count, nums)
208
+ @header = populate_hmap_header(nums, entries)
209
+ @buckets = add_bucket(buckets, nums)
210
+ end
211
+
212
+ def num_buckets(count, pow2)
213
+ if count < 8
214
+ pow2 <<= 1 if count * 4 >= pow2 * 3
215
+ pow2 < 8 ? 8 : pow2
216
+ else
217
+ index = count > 341 ? 2 : -3
218
+ padding = count / 85 % 7 + index
219
+ Utils.next_power_of_two(count * 3 + padding)
220
+ end
221
+ end
222
+
223
+ def entries(count, nums)
224
+ return count if nums == 8
225
+
226
+ last_pow = nums >> 1
227
+ index = last_pow < 1024 ? 3 : -2
228
+ count - (last_pow + 1 + index) / 3 + 1 + last_pow
229
+ end
230
+
231
+ # @return [String] the serialized fields of the mafile
232
+ def serialize
233
+ @header.serialize + @buckets.inject('') do |sum, bucket|
234
+ sum += if bucket.nil?
235
+ empty_b = [HEADER_CONST[:HMAP_EMPTY_BUCKT_KEY]]*3
236
+ empty_b.pack('L<3')
237
+ else
238
+ bucket
239
+ end
240
+ sum
241
+ end
242
+ end
243
+
244
+ def add_bucket(buckets, num)
245
+ buckets.each_with_object(Array.new(num)) do |bucket, sum|
246
+ serialize = bucket.serialize
247
+ i = Utils.index_of_range(bucket.uuid, num)
248
+ loop do
249
+ sum[i] = serialize if sum[i].nil?
250
+ break if serialize == sum[i]
251
+
252
+ i = Utils.index_of_range(i += 1, num)
253
+ end
254
+ end
255
+ end
256
+
257
+ def populate_hmap_header(num_buckets, entries)
258
+ strings_offset = HMapHeader.bytesize + HMapBucket.bytesize * num_buckets
259
+ HMapHeader.new(HEADER_CONST[:HMAP_HEADER_MAGIC_NUMBER],
260
+ HEADER_CONST[:HMAP_HEADER_VERSION], 0, strings_offset, entries, num_buckets, 0)
261
+ end
262
+ end
263
+ end
264
+
@@ -0,0 +1,136 @@
1
+ require 'cocoapods'
2
+
3
+ module HMap
4
+ # A collection of utility functions used throughout cocoapods-hmap-prebuilt.
5
+ module Utils
6
+ HEADER_EXTENSIONS = Pod::Sandbox::FileAccessor::HEADER_EXTENSIONS
7
+
8
+ def self.index_of_range(num, range)
9
+ num &= range - 1
10
+ num
11
+ end
12
+
13
+ def self.power_of_two?(num)
14
+ num != 0 && (num & (num - 1)).zero?
15
+ end
16
+
17
+ def self.next_power_of_two(num)
18
+ num |= (num >> 1)
19
+ num |= (num >> 2)
20
+ num |= (num >> 4)
21
+ num |= (num >> 8)
22
+ num |= (num >> 16)
23
+ num |= (num >> 32)
24
+ num + 1
25
+ end
26
+
27
+ def self.hash_set_value(hash, *args)
28
+ args.each do |arg|
29
+ hash.merge(arg)
30
+ end
31
+ hash
32
+ end
33
+
34
+ def self.specialize_format(format, swapped)
35
+ modifier = swapped ? '<' : '>'
36
+ format.tr('=', modifier)
37
+ end
38
+
39
+ def self.string_downcase_hash(str)
40
+ str.downcase.bytes.inject(0) do |sum, value|
41
+ sum += value * 13
42
+ sum
43
+ end
44
+ end
45
+
46
+ def self.update_changed_file(path, contents)
47
+ if path.exist?
48
+ content_stream = StringIO.new(contents)
49
+ identical = File.open(path, 'rb') { |f| FileUtils.compare_stream(f, content_stream) }
50
+ return if identical
51
+ end
52
+ path.dirname.mkpath
53
+ File.open(path, 'w') { |f| f.write(contents) }
54
+ end
55
+
56
+ def self.swapped_magic?(magic, version)
57
+ magic.eql?(HEADER_CONST[:HMAP_SWAPPED_MAGIC]) && version.eql?(HEADER_CONST[:HMAP_SWAPPED_VERSION])
58
+ end
59
+
60
+ def self.magic?(magic)
61
+ magic.eql?(HEADER_CONST[:HMAP_SWAPPED_MAGIC]) || magic.eql?(HEADER_CONST[:HMAP_HEADER_MAGIC_NUMBER])
62
+ end
63
+
64
+ def self.safe_encode(string, target_encoding)
65
+ string.encode(target_encoding)
66
+ rescue Encoding::InvalidByteSequenceError
67
+ string.force_encoding(target_encoding)
68
+ rescue Encoding::UndefinedConversionError
69
+ string.encode(target_encoding, fallback: lambda { |c|
70
+ c.force_encoding(target_encoding)
71
+ })
72
+ end
73
+
74
+ def self.clean_target_build_setting(targets, build_setting)
75
+ target_xcconfig_path(targets) do |xc|
76
+ clean_build_setting_to_xcconfig(xc, build_setting)
77
+ end
78
+ end
79
+
80
+ def self.target_xcconfig_path(targets)
81
+ targets.each do |target|
82
+ raise ClassIncludedError.new(target.class, Pod::Target) unless target.is_a?(Pod::Target)
83
+
84
+ config_h = Pod::Target.instance_method(:build_settings).bind(target).call
85
+ config_h.each_key do |configuration_name|
86
+ xcconfig = target.xcconfig_path(configuration_name)
87
+ yield(xcconfig) if block_given?
88
+ end
89
+ end
90
+ end
91
+
92
+ def self.change_xcconfig_header_search_path(xcconfig, hmap_h, use_headermap: true, save_origin: true)
93
+ hmap_header_serach_paths = hmap_h.inject('') do |sum, hmap_n|
94
+ hmap_pod_root_path = "${PODS_ROOT}/Headers/#{HMAP_DIR_NAME}/#{hmap_n}"
95
+ sum + "\"#{hmap_pod_root_path}\" "
96
+ end
97
+ save_build_setting_to_xcconfig(xcconfig, hmap_header_serach_paths, HEAD_SEARCH_PATHS, save_origin: save_origin) do |xc|
98
+ xc.attributes['USE_HEADERMAP'] = 'NO' unless use_headermap
99
+ end
100
+ end
101
+
102
+ def self.save_build_setting_to_xcconfig(path, value, build_setting, save_origin: true)
103
+ xc = Xcodeproj::Config.new(path)
104
+ save_origin_build_setting = "SAVE_#{build_setting}"
105
+ hmap_build_setting = "HMAP_PREBUILT_#{build_setting}"
106
+ origin_build_setting = xc.attributes[build_setting]
107
+
108
+ if !origin_build_setting.nil? && !origin_build_setting.include?(hmap_build_setting)
109
+ xc.attributes[save_origin_build_setting] =
110
+ origin_build_setting
111
+ end
112
+
113
+ save_origin_build_setting_value = xc.attributes[save_origin_build_setting]
114
+ value = "#{value} ${#{save_origin_build_setting}}" if save_origin && !save_origin_build_setting_value.nil?
115
+ xc.attributes[hmap_build_setting] = value
116
+ xc.attributes[build_setting] = "${#{hmap_build_setting}}"
117
+ yield(xc) if block_given?
118
+ xc.save_as(path)
119
+ end
120
+
121
+ def self.clean_build_setting_to_xcconfig(path, build_setting)
122
+ xc = Xcodeproj::Config.new(path)
123
+ save_origin_build_setting = "SAVE_#{build_setting}"
124
+ hmap_build_setting = "HMAP_PREBUILT_#{build_setting}"
125
+ return if xc.attributes[hmap_build_setting].nil?
126
+
127
+ xc.attributes[build_setting] = xc.attributes[save_origin_build_setting]
128
+ xc.attributes.delete(save_origin_build_setting)
129
+ xc.attributes.delete(hmap_build_setting)
130
+ xc.attributes['USE_HEADERMAP'] = 'YES'
131
+ xc.attributes.delete(build_setting) if xc.attributes[build_setting].nil?
132
+ xc.save_as(path)
133
+ puts "\t -xcconfig path: #{path} clean finish."
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,3 @@
1
+ module CocoapodsHmapPrebuilt
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,29 @@
1
+
2
+ module HMap
3
+ # A representation of some unspecified hmap data.
4
+ class HMapView
5
+ # @return [String] the raw hmap data
6
+ attr_reader :raw_data
7
+
8
+ # @return [Symbol] the endianness of the data (`:big` or `:little`)
9
+ attr_reader :endianness
10
+
11
+ # @return [Integer] the offset of the relevant data (in {#raw_data})
12
+ attr_reader :offset
13
+
14
+ # Creates a new HMapView.
15
+ def initialize(raw_data, endianness, offset)
16
+ @raw_data = raw_data
17
+ @endianness = endianness
18
+ @offset = offset
19
+ end
20
+
21
+ # @return [Hash] a hash representation of this {HMapView}.
22
+ def to_h
23
+ {
24
+ 'endianness' => endianness,
25
+ 'offset' => offset
26
+ }
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,11 @@
1
+ require 'cocoapods-hmap-prebuilt/command/hmap_writer'
2
+ require 'cocoapods-hmap-prebuilt/command/hmap_reader'
3
+
4
+ module CocoapodsHmapPrebuiltHook
5
+ Pod::HooksManager.register('cocoapods-hmap-prebuilt', :post_install) do
6
+ Command::HMapWriter.run(["--project-directory=#{Config.instance.installation_root}", "--nosave-origin-header-search-paths"])
7
+ end
8
+ Pod::HooksManager.register('cocoapods-hmap-prebuilt', :post_update) do
9
+ Command::HMapWriter.run(["--project-directory=#{Config.instance.installation_root}", "--nosave-origin-header-search-paths"])
10
+ end
11
+ end
metadata ADDED
@@ -0,0 +1,132 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cocoapods-hmap-prebuilt
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - EricLou
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-08-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.1'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: coveralls
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: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: cocoapods
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '1.6'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '1.6'
83
+ description: A short description of cocoapods-hmap-prebuilt.
84
+ email:
85
+ - 499304609@qq.com
86
+ executables:
87
+ - hmap-prebuilt-read
88
+ - hmap-prebuilt-write
89
+ extensions: []
90
+ extra_rdoc_files: []
91
+ files:
92
+ - LICENSE
93
+ - README.md
94
+ - bin/hmap-prebuilt-read
95
+ - bin/hmap-prebuilt-write
96
+ - lib/cocoapods-hmap-prebuilt.rb
97
+ - lib/cocoapods-hmap-prebuilt/command/hmap_reader.rb
98
+ - lib/cocoapods-hmap-prebuilt/command/hmap_writer.rb
99
+ - lib/cocoapods-hmap-prebuilt/hmap_exceptions.rb
100
+ - lib/cocoapods-hmap-prebuilt/hmap_file.rb
101
+ - lib/cocoapods-hmap-prebuilt/hmap_file_reader.rb
102
+ - lib/cocoapods-hmap-prebuilt/hmap_file_writer.rb
103
+ - lib/cocoapods-hmap-prebuilt/hmap_helper.rb
104
+ - lib/cocoapods-hmap-prebuilt/hmap_struct.rb
105
+ - lib/cocoapods-hmap-prebuilt/hmap_utils.rb
106
+ - lib/cocoapods-hmap-prebuilt/hmap_version.rb
107
+ - lib/cocoapods-hmap-prebuilt/hmap_view.rb
108
+ - lib/cocoapods_plugin.rb
109
+ homepage: http://gitlab.webuy.ai/iOS/cocoapod-hamp-prebuilt.git
110
+ licenses:
111
+ - MIT
112
+ metadata: {}
113
+ post_install_message:
114
+ rdoc_options: []
115
+ require_paths:
116
+ - lib
117
+ required_ruby_version: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ version: '2.5'
122
+ required_rubygems_version: !ruby/object:Gem::Requirement
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
127
+ requirements: []
128
+ rubygems_version: 3.0.3
129
+ signing_key:
130
+ specification_version: 4
131
+ summary: A longer description of cocoapods-hmap-prebuilt.
132
+ test_files: []