cocoapods-mapfile 0.1.6
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 +7 -0
- data/LICENSE +21 -0
- data/README.md +106 -0
- data/bin/hmap_reader +12 -0
- data/bin/hmap_writer +11 -0
- data/lib/cocoapods-hmap/command/hmap_gen.rb +52 -0
- data/lib/cocoapods-hmap/command/hmap_reader.rb +42 -0
- data/lib/cocoapods-hmap/exceptions.rb +33 -0
- data/lib/cocoapods-hmap/hmap_reader.rb +96 -0
- data/lib/cocoapods-hmap/hmap_struct.rb +267 -0
- data/lib/cocoapods-hmap/hmap_writer.rb +145 -0
- data/lib/cocoapods-hmap/mapfile.rb +33 -0
- data/lib/cocoapods-hmap/pods_helper.rb +57 -0
- data/lib/cocoapods-hmap/utils.rb +140 -0
- data/lib/cocoapods-hmap/version.rb +5 -0
- data/lib/cocoapods-hmap/view.rb +33 -0
- data/lib/cocoapods_hmap.rb +15 -0
- data/lib/cocoapods_plugin.rb +13 -0
- metadata +133 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: cc6a56eb46579631d759dfdcabf1b96f05291024207fb6d965ff151dd1b4acb9
|
4
|
+
data.tar.gz: 5815e25f42759074cddd0c76a08c3f23fd6b56f6fd59c92394ef2adf20c149d7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9bb22b8025a237b09215a30808d615929f13f2aec2fe2cb96b8dc5f1a20377c7d22ffcc94b1af5d56680d70223128f39707153aa724d7bfb37353425e7260ee8
|
7
|
+
data.tar.gz: 0a34f3b7e122d0efa02b976de35d150f6cdab661a3f051864c57e6db63d47b0667a97a2d0fa22608ef60bc338b31f45abc884eb1864b5baa6a4f9fee826c5b71
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2021 Cat1237
|
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
|
13
|
+
all 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
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
# cocoapods-hmap
|
2
|
+
|
3
|
+
[](https://raw.githubusercontent.com/wangson1237/SYCSSColor/master/LICENSE)
|
4
|
+
|
5
|
+
A CocoaPods plugin which can gen/read header map file.
|
6
|
+
|
7
|
+
**hmap-gen** is able to scan the header files of the target referenced components in the specified Cocoapods project, and generates a header map file that public to all the components
|
8
|
+
as well as generates a public and private header map file for each referenced component.
|
9
|
+
|
10
|
+
A hmap file includes four types of headers:
|
11
|
+
|
12
|
+
- header.h
|
13
|
+
- <module/header.h> **based on podspec**
|
14
|
+
- <project_name/header.h> **based on podspec**
|
15
|
+
- <podspec source header/**/header.h> **based on podspec**
|
16
|
+
|
17
|
+
At the same time, **hmap-reader** can read the header, bucktes, string_table information saved in the header map file.
|
18
|
+
|
19
|
+
- ✅ It can read hmap file.
|
20
|
+
|
21
|
+
- ✅ It can generate header map file.
|
22
|
+
|
23
|
+
## Installation
|
24
|
+
|
25
|
+
Add this line to your application's Gemfile:
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
gem 'cocoapods-mapfile'
|
29
|
+
```
|
30
|
+
|
31
|
+
And then execute:
|
32
|
+
|
33
|
+
```shell
|
34
|
+
# bundle install
|
35
|
+
$ bundle install
|
36
|
+
```
|
37
|
+
|
38
|
+
Or install it yourself as:
|
39
|
+
|
40
|
+
```shell
|
41
|
+
# gem install
|
42
|
+
$ gem install cocoapods-mapfile
|
43
|
+
```
|
44
|
+
|
45
|
+
## Usage
|
46
|
+
|
47
|
+
The command should be executed in directory that contains podfile.
|
48
|
+
|
49
|
+
```shell
|
50
|
+
# write the hmap file to podfile/Pods/Headers/HMap
|
51
|
+
$ pod hmap-gen
|
52
|
+
|
53
|
+
# write the hmap file to /project/dir/Pods/Headers/HMap
|
54
|
+
$ pod hmap-gen --project-directory=/project/dir/
|
55
|
+
|
56
|
+
# write the hmap file to /project/dir/Pods/Headers/HMap and no save origin [HEADER_SEARCH_PATHS]
|
57
|
+
$ pod hmap-gen --project-directory=/project/dir/ --nosave-origin-header-search-paths
|
58
|
+
|
59
|
+
# cleanup the hmap file
|
60
|
+
$ pod hmap-gen --clean-hmap
|
61
|
+
|
62
|
+
# read the hmap file from /hmap/dir/file
|
63
|
+
$ pod hmap-reader --hmap-path=/hmap/dir/file
|
64
|
+
```
|
65
|
+
|
66
|
+
At same time, you can put this line in your podfile:
|
67
|
+
|
68
|
+
```rb
|
69
|
+
plugin 'cocoapods-mapfile'
|
70
|
+
```
|
71
|
+
This was equl:
|
72
|
+
```rb
|
73
|
+
pod hmap-gen --project-directory=/project/dir/ --nosave-origin-header-search-paths
|
74
|
+
```
|
75
|
+
|
76
|
+
Every time you execute pod install or pod update, `cocoapods-mapfile` will automatically generate a `header map file` for you and modify `HEAD_SEARCH_PATHS`.
|
77
|
+
|
78
|
+
### Option && Flags
|
79
|
+
|
80
|
+
`hmap-gen/hmap-writer`:
|
81
|
+
|
82
|
+
- `--project-directory=/project/dir/`: The path to the root of the project directory.
|
83
|
+
- `--nosave-origin-header-search-paths`: This option will not save xcconfig origin [HEADER_SEARCH_PATHS] and put `hmap file path` first.
|
84
|
+
- `--clean-hmap`: This option will clean up all `hmap-gen/hmap-writer` setup for hmap.
|
85
|
+
|
86
|
+
`hmap-reader`:
|
87
|
+
|
88
|
+
- `--hmap-path=/hmap/dir/file`: The path of the hmap file.
|
89
|
+
|
90
|
+
## Command Line Tool
|
91
|
+
|
92
|
+
Installing the 'cocoapods-mapfile' gem will also install two command-line tool `hmap_reader` and `hmap-writer` which you can use to generate header map file and read hmap file.
|
93
|
+
|
94
|
+
For more information consult `hmap_reader --help` or `hmap_writer --help`.
|
95
|
+
|
96
|
+
## Contributing
|
97
|
+
|
98
|
+
Bug reports and pull requests are welcome on GitHub at [cocoapods-hmap](https://github.com/Cat1237/cocoapods-hmap). This project is intended to be a safe, welcoming space for collaboration.
|
99
|
+
|
100
|
+
## License
|
101
|
+
|
102
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
103
|
+
|
104
|
+
## Code of Conduct
|
105
|
+
|
106
|
+
Everyone interacting in the Cocoapods::Hmap project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/cocoapods-hmap/blob/master/CODE_OF_CONDUCT.md).
|
data/bin/hmap_reader
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
|
5
|
+
if $PROGRAM_NAME == __FILE__
|
6
|
+
ENV['BUNDLE_GEMFILE'] = File.expand_path('../Gemfile', __dir__)
|
7
|
+
require 'bundler/setup'
|
8
|
+
end
|
9
|
+
|
10
|
+
require 'cocoapods-hmap/command/hmap_reader'
|
11
|
+
|
12
|
+
Pod::Command::HMapReader.run(ARGV)
|
data/bin/hmap_writer
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
if $PROGRAM_NAME == __FILE__
|
5
|
+
ENV['BUNDLE_GEMFILE'] = File.expand_path('../Gemfile', __dir__)
|
6
|
+
require 'bundler/setup'
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'cocoapods-hmap/command/hmap_gen'
|
10
|
+
|
11
|
+
Pod::Command::HMapGen.run(ARGV)
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cocoapods_hmap'
|
4
|
+
require 'cocoapods'
|
5
|
+
|
6
|
+
module Pod
|
7
|
+
class Command
|
8
|
+
# hmap file gen cmd
|
9
|
+
class HMapGen < Command
|
10
|
+
# summary
|
11
|
+
self.summary = 'Analyzes the dependencies and gen each dependencie mapfile.'
|
12
|
+
|
13
|
+
self.description = <<-DESC
|
14
|
+
Analyzes the dependencies of any cocoapods projects and gen each dependencie mapfile.
|
15
|
+
DESC
|
16
|
+
|
17
|
+
def initialize(argv)
|
18
|
+
super
|
19
|
+
project_directory = argv.option('project-directory')
|
20
|
+
@save_origin_header_search_paths = !argv.flag?('nosave-origin-header-search-paths', false)
|
21
|
+
@clean_hmap = argv.flag?('clean-hmap', false)
|
22
|
+
|
23
|
+
return if project_directory.nil?
|
24
|
+
|
25
|
+
@project_directory = Pathname.new(project_directory).expand_path
|
26
|
+
config.installation_root = @project_directory
|
27
|
+
end
|
28
|
+
|
29
|
+
def validate!
|
30
|
+
super
|
31
|
+
verify_podfile_exists!
|
32
|
+
end
|
33
|
+
|
34
|
+
# help
|
35
|
+
def self.options
|
36
|
+
[
|
37
|
+
['--project-directory=/project/dir/', 'The path to the root of the project
|
38
|
+
directory'],
|
39
|
+
['--nosave-origin-header-search-paths', 'This option will not save xcconfig origin [HEADER_SEARCH_PATHS] and put hmap file first'],
|
40
|
+
['--clean-hmap', 'This option will clean up all hmap-gen setup for hmap.']
|
41
|
+
].concat(super)
|
42
|
+
end
|
43
|
+
|
44
|
+
def run
|
45
|
+
UI.section "\n[hmap-gen] start.............." do
|
46
|
+
HMap::MapFileWriter.new(@save_origin_header_search_paths, @clean_hmap)
|
47
|
+
end
|
48
|
+
UI.puts('[hmap-gen] finish..............')
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
|
3
|
+
require 'cocoapods_hmap'
|
4
|
+
require 'cocoapods'
|
5
|
+
|
6
|
+
module Pod
|
7
|
+
class Command
|
8
|
+
# hmap file reader cmd
|
9
|
+
class HMapReader < Command
|
10
|
+
self.summary = 'Read mapfile and puts result.'
|
11
|
+
|
12
|
+
self.description = <<-DESC
|
13
|
+
Read mapfile and puts result, header, buckets, string_table.
|
14
|
+
DESC
|
15
|
+
|
16
|
+
def initialize(argv)
|
17
|
+
super
|
18
|
+
mapfile_path = argv.option('hmap-path')
|
19
|
+
@mapfile_path = Pathname.new(mapfile_path).expand_path unless mapfile_path.nil?
|
20
|
+
end
|
21
|
+
|
22
|
+
def validate!
|
23
|
+
super
|
24
|
+
banner! if help?
|
25
|
+
raise '[ERROR]: --hmap-path no set'.red unless File.exist?(@mapfile_path)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.options
|
29
|
+
[
|
30
|
+
['--hmap-path=/hmap/dir/file', 'The path of the hmap file']
|
31
|
+
].concat(super)
|
32
|
+
end
|
33
|
+
|
34
|
+
def run
|
35
|
+
UI.section "\n[hmap-reader] start..............\n".yellow do
|
36
|
+
HMap::MapFileReader.new(@mapfile_path)
|
37
|
+
end
|
38
|
+
UI.puts("\n[hmap-reader] finish..............\n".yellow)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module HMap
|
4
|
+
# A generic HMap error in execution.
|
5
|
+
class HMapError < RuntimeError
|
6
|
+
end
|
7
|
+
|
8
|
+
# Raised when a file is not a HMap.
|
9
|
+
class NotAHMapOError < HMapError
|
10
|
+
end
|
11
|
+
|
12
|
+
# Raised when a file is too short to be a valid HMap file.
|
13
|
+
class TruncatedFileError < NotAHMapOError
|
14
|
+
def initialize
|
15
|
+
super 'File is too short to be a valid HMap'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Raised when a file's magic bytes are not valid HMap magic.
|
20
|
+
class MagicError < NotAHMapOError
|
21
|
+
# @param num [Integer] the unknown number
|
22
|
+
def initialize(magic)
|
23
|
+
super format('Unrecognized HMap magic: 0x%02<magic>x', magic: magic)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Raised when a class is not the class of obj.
|
28
|
+
class ClassIncludedError < HMapError
|
29
|
+
def initialize(cls1, cls2)
|
30
|
+
super format('%<cls1>s must be the %<cls2>s of obj', cls1: cls1, cls2: cls2)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module HMap
|
4
|
+
# hmap file reader
|
5
|
+
class MapFileReader
|
6
|
+
# @return [String, nil] the filename loaded from, or nil if loaded from a binary
|
7
|
+
# string
|
8
|
+
attr_reader :filename
|
9
|
+
# # @return [Hash] any parser options that the instance was created with
|
10
|
+
# attr_reader :options
|
11
|
+
|
12
|
+
# @return true/false the swapped of the mapfile
|
13
|
+
attr_reader :swapped
|
14
|
+
|
15
|
+
# @return [HMap::HMapHeader]
|
16
|
+
attr_reader :header
|
17
|
+
|
18
|
+
# @return [Hash<HMap::HMapBucket => HMap::HMapBucketStr>] an array of the file's bucktes
|
19
|
+
# @note bucktes are provided in order of ascending offset.
|
20
|
+
attr_reader :bucktes
|
21
|
+
|
22
|
+
def initialize(path)
|
23
|
+
raise ArgumentError, "#{path}: no such file" unless File.file?(path)
|
24
|
+
|
25
|
+
@filename = path
|
26
|
+
@raw_data = File.open(@filename, 'rb', &:read)
|
27
|
+
populate_fields
|
28
|
+
puts description
|
29
|
+
end
|
30
|
+
|
31
|
+
# Populate the instance's fields with the raw HMap data.
|
32
|
+
# @return [void]
|
33
|
+
# @note This method is public, but should (almost) never need to be called.
|
34
|
+
def populate_fields
|
35
|
+
@header = populate_hmap_header
|
36
|
+
string_t = @raw_data[header.strings_offset..-1]
|
37
|
+
@bucktes = populate_buckets do |bucket|
|
38
|
+
bucket_s = bucket.to_a.map do |key|
|
39
|
+
string_t[key..-1].match(/[^\0]+/)[0]
|
40
|
+
end
|
41
|
+
HMapBucketStr.new(*bucket_s)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
# The file's HMapheader structure.
|
48
|
+
# @return [HMap::HMapHeader]
|
49
|
+
# @raise [TruncatedFileError] if the file is too small to have a valid header
|
50
|
+
# @api private
|
51
|
+
def populate_hmap_header
|
52
|
+
raise TruncatedFileError if @raw_data.size < HMapHeader.bytesize + 8 * HMapBucket.bytesize
|
53
|
+
|
54
|
+
populate_and_check_magic
|
55
|
+
HMapHeader.new_from_bin(swapped, @raw_data[0, HMapHeader.bytesize])
|
56
|
+
end
|
57
|
+
|
58
|
+
# Read just the file's magic number and check its validity.
|
59
|
+
# @return [Integer] the magic
|
60
|
+
# @raise [MagicError] if the magic is not valid HMap magic
|
61
|
+
# @api private
|
62
|
+
def populate_and_check_magic
|
63
|
+
magic = @raw_data[0..3].unpack1('N')
|
64
|
+
raise MagicError, magic unless Utils.magic?(magic)
|
65
|
+
|
66
|
+
version = @raw_data[4..5].unpack1('n')
|
67
|
+
@swapped = Utils.swapped_magic?(magic, version)
|
68
|
+
end
|
69
|
+
|
70
|
+
# All buckets in the file.
|
71
|
+
# @return [Array<HMap::HMapBucket>] an array of buckets
|
72
|
+
# @api private
|
73
|
+
def populate_buckets
|
74
|
+
bucket_offset = header.class.bytesize
|
75
|
+
bucktes = []
|
76
|
+
header.num_buckets.times do |i|
|
77
|
+
bucket = HMapBucket.new_from_bin(swapped, @raw_data[bucket_offset, HMapBucket.bytesize])
|
78
|
+
bucket_offset += HMapBucket.bytesize
|
79
|
+
next if bucket.key == HEADER_CONST[:HMAP_EMPTY_BUCKT_KEY]
|
80
|
+
|
81
|
+
bucktes[i] = { bucket => yield(bucket) }
|
82
|
+
end
|
83
|
+
bucktes
|
84
|
+
end
|
85
|
+
|
86
|
+
# description
|
87
|
+
def description
|
88
|
+
sum = " Header map: #{filename}\n" + header.description
|
89
|
+
bucktes.each_with_index do |buckte_h, index|
|
90
|
+
sum += "\t- Bucket: #{index}" + Utils.safe_encode(buckte_h.values[0].description, 'UTF-8') unless buckte_h.nil?
|
91
|
+
sum
|
92
|
+
end
|
93
|
+
sum
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,267 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# require 'cocoapods-hmap/view'
|
4
|
+
|
5
|
+
module HMap
|
6
|
+
HEADER_CONST = {
|
7
|
+
HMAP_HEADER_MAGIC_NUMBER: 0x686d6170,
|
8
|
+
HMAP_HEADER_VERSION: 0x0001,
|
9
|
+
HMAP_EMPTY_BUCKT_KEY: 0,
|
10
|
+
HMAP_SWAPPED_MAGIC: 0x70616d68,
|
11
|
+
HMAP_SWAPPED_VERSION: 0x0100
|
12
|
+
}.freeze
|
13
|
+
|
14
|
+
# A general purpose pseudo-structure.
|
15
|
+
# @abstract
|
16
|
+
class HMapStructure
|
17
|
+
# The String#unpack format of the data structure.
|
18
|
+
# @return [String] the unpacking format
|
19
|
+
# @api private
|
20
|
+
FORMAT = ''
|
21
|
+
|
22
|
+
# The size of the data structure, in bytes.
|
23
|
+
# @return [Integer] the size, in bytes
|
24
|
+
# @api private
|
25
|
+
SIZEOF = 0
|
26
|
+
|
27
|
+
SWAPPED = true
|
28
|
+
|
29
|
+
# @return [Integer] the size, in bytes, of the represented structure.
|
30
|
+
def self.bytesize
|
31
|
+
self::SIZEOF
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.format
|
35
|
+
self::FORMAT
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.swapped?
|
39
|
+
self::SWAPPED
|
40
|
+
end
|
41
|
+
|
42
|
+
# @param endianness [Symbol] either `:big` or `:little`
|
43
|
+
# @param bin [String] the string to be unpacked into the new structure
|
44
|
+
# @return [HMap::HMapStructure] the resulting structure
|
45
|
+
# @api private
|
46
|
+
def self.new_from_bin(swapped, bin)
|
47
|
+
format = Utils.specialize_format(self::FORMAT, swapped)
|
48
|
+
new(*bin.unpack(format))
|
49
|
+
end
|
50
|
+
|
51
|
+
def serialize
|
52
|
+
[].pack(format)
|
53
|
+
end
|
54
|
+
|
55
|
+
# @return [Hash] a hash representation of this {HMapStructure}.
|
56
|
+
def to_h
|
57
|
+
{
|
58
|
+
'structure' => {
|
59
|
+
'format' => self.class::FORMAT,
|
60
|
+
'bytesize' => self.class.bytesize
|
61
|
+
}
|
62
|
+
}
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# HMapHeader structure.
|
67
|
+
# @see https://clang.llvm.org/doxygen/structclang_1_1HMapHeader.html
|
68
|
+
# @abstract
|
69
|
+
class HMapHeader < HMapStructure
|
70
|
+
# @return [HMap::HMapView, nil] the raw view associated with the load command,
|
71
|
+
# or nil if the HMapHeader was created via {create}.
|
72
|
+
attr_reader :num_entries, :magic, :version, :reserved, :strings_offset, :num_buckets, :max_value_length
|
73
|
+
|
74
|
+
FORMAT = 'L=1S=2L4'
|
75
|
+
# @see HMapStructure::SIZEOF
|
76
|
+
# @api private
|
77
|
+
SIZEOF = 24
|
78
|
+
|
79
|
+
# @api private
|
80
|
+
def initialize(magic, version, reserved, strings_offset, num_entries, num_buckets, max_value_length)
|
81
|
+
@magic = magic
|
82
|
+
@version = version
|
83
|
+
@reserved = reserved
|
84
|
+
@strings_offset = strings_offset
|
85
|
+
@num_entries = num_entries
|
86
|
+
@num_buckets = num_buckets
|
87
|
+
@max_value_length = max_value_length
|
88
|
+
super()
|
89
|
+
end
|
90
|
+
|
91
|
+
# @return [String] the serialized fields of the mafile
|
92
|
+
def serialize
|
93
|
+
format = Utils.specialize_format(FORMAT, SWAPPED)
|
94
|
+
[magic, version, reserved, strings_offset, num_entries, num_buckets, max_value_length].pack(format)
|
95
|
+
end
|
96
|
+
|
97
|
+
def description
|
98
|
+
<<-DESC
|
99
|
+
Hash bucket count: #{@num_buckets}
|
100
|
+
String table entry count: #{@num_entries}
|
101
|
+
Max value length: #{@max_value_length}
|
102
|
+
DESC
|
103
|
+
end
|
104
|
+
|
105
|
+
def to_h
|
106
|
+
{
|
107
|
+
'magic' => magic,
|
108
|
+
'version' => version,
|
109
|
+
'reserved' => reserved,
|
110
|
+
'strings_offset' => strings_offset,
|
111
|
+
'num_entries' => num_entries,
|
112
|
+
'num_buckets' => num_buckets,
|
113
|
+
'max_value_length' => max_value_length
|
114
|
+
}.merge super
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# HMapBucketStr => HMapBucket.
|
119
|
+
# @see https://clang.llvm.org/doxygen/structclang_1_1HMapHeader.html
|
120
|
+
# @abstract
|
121
|
+
class HMapBucketStr
|
122
|
+
attr_reader :uuid, :key, :perfix, :suffix
|
123
|
+
|
124
|
+
def initialize(key, perfix, suffix)
|
125
|
+
@uuid = Utils.string_downcase_hash(key)
|
126
|
+
@key = key
|
127
|
+
@perfix = perfix
|
128
|
+
@suffix = suffix
|
129
|
+
@str_ins = {}
|
130
|
+
end
|
131
|
+
|
132
|
+
def bucket_to_string(headers, index)
|
133
|
+
bucket = [key, perfix, suffix]
|
134
|
+
bucket.inject('') do |sum, arg|
|
135
|
+
if headers[arg].nil?
|
136
|
+
headers[arg] = sum.length + index
|
137
|
+
sum += "#{Utils.safe_encode(arg, 'ASCII-8BIT')}\0"
|
138
|
+
end
|
139
|
+
@str_ins[arg] = headers[arg]
|
140
|
+
sum
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def bucket
|
145
|
+
HMapBucket.new(@str_ins[@key], @str_ins[@perfix], @str_ins[@suffix])
|
146
|
+
end
|
147
|
+
|
148
|
+
# @return [String] the serialized fields of the mafile
|
149
|
+
def serialize
|
150
|
+
bucket.serialize
|
151
|
+
end
|
152
|
+
|
153
|
+
def description
|
154
|
+
<<-DESC
|
155
|
+
Key #{@key} -> Prefix #{@perfix}, Suffix #{@suffix}
|
156
|
+
DESC
|
157
|
+
end
|
158
|
+
|
159
|
+
def to_h
|
160
|
+
{
|
161
|
+
'key' => { 'index' => str_ins[@key], 'key' => @key },
|
162
|
+
'perfix' => { 'index' => str_ins[@perfix], 'perfix' => @perfix },
|
163
|
+
'suffix' => { 'index' => str_ins[@suffix], 'suffix' => @suffix }
|
164
|
+
}
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
# HMapBucket structure.
|
169
|
+
# @see https://clang.llvm.org/doxygen/structclang_1_1HMapHeader.html
|
170
|
+
# @abstract
|
171
|
+
class HMapBucket < HMapStructure
|
172
|
+
attr_accessor :key, :perfix, :suffix
|
173
|
+
|
174
|
+
SIZEOF = 12
|
175
|
+
FORMAT = 'L=3'
|
176
|
+
|
177
|
+
def initialize(key, perfix, suffix)
|
178
|
+
@key = key
|
179
|
+
@perfix = perfix
|
180
|
+
@suffix = suffix
|
181
|
+
super()
|
182
|
+
end
|
183
|
+
|
184
|
+
# @return [String] the serialized fields of the mafile
|
185
|
+
def serialize
|
186
|
+
format = Utils.specialize_format(FORMAT, SWAPPED)
|
187
|
+
[key, perfix, suffix].pack(format)
|
188
|
+
end
|
189
|
+
|
190
|
+
def to_a
|
191
|
+
[key, perfix, suffix]
|
192
|
+
end
|
193
|
+
|
194
|
+
def to_h
|
195
|
+
{
|
196
|
+
'key' => key,
|
197
|
+
'perfix' => perfix,
|
198
|
+
'suffix' => suffix
|
199
|
+
}.merge super
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
# HMap blobs.
|
204
|
+
class HMapData
|
205
|
+
def initialize(buckets)
|
206
|
+
super()
|
207
|
+
count = buckets.count
|
208
|
+
nums = num_buckets(count, Utils.next_power_of_two(count))
|
209
|
+
entries = entries(count, nums)
|
210
|
+
@header = populate_hmap_header(nums, entries)
|
211
|
+
@buckets = add_bucket(buckets, nums)
|
212
|
+
end
|
213
|
+
|
214
|
+
def num_buckets(count, pow2)
|
215
|
+
if count < 8
|
216
|
+
pow2 <<= 1 if count * 4 >= pow2 * 3
|
217
|
+
pow2 < 8 ? 8 : pow2
|
218
|
+
else
|
219
|
+
index = count > 341 ? 2 : -3
|
220
|
+
padding = count / 85 % 7 + index
|
221
|
+
Utils.next_power_of_two(count * 3 + padding)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
def entries(count, nums)
|
226
|
+
return count if nums == 8
|
227
|
+
|
228
|
+
last_pow = nums >> 1
|
229
|
+
index = last_pow < 1024 ? 3 : -2
|
230
|
+
count - (last_pow + 1 + index) / 3 + 1 + last_pow
|
231
|
+
end
|
232
|
+
|
233
|
+
# @return [String] the serialized fields of the mafile
|
234
|
+
def serialize
|
235
|
+
@header.serialize + @buckets.inject('') do |sum, bucket|
|
236
|
+
sum += if bucket.nil?
|
237
|
+
empty_b = [HEADER_CONST[:HMAP_EMPTY_BUCKT_KEY]]*3
|
238
|
+
empty_b.pack('L<3')
|
239
|
+
else
|
240
|
+
bucket
|
241
|
+
end
|
242
|
+
sum
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
private
|
247
|
+
|
248
|
+
def add_bucket(buckets, num)
|
249
|
+
buckets.each_with_object(Array.new(num)) do |bucket, sum|
|
250
|
+
serialize = bucket.serialize
|
251
|
+
i = Utils.index_of_range(bucket.uuid, num)
|
252
|
+
loop do
|
253
|
+
sum[i] = serialize if sum[i].nil?
|
254
|
+
break if serialize == sum[i]
|
255
|
+
|
256
|
+
i = Utils.index_of_range(i += 1, num)
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
def populate_hmap_header(num_buckets, entries)
|
262
|
+
strings_offset = HMapHeader.bytesize + HMapBucket.bytesize * num_buckets
|
263
|
+
HMapHeader.new(HEADER_CONST[:HMAP_HEADER_MAGIC_NUMBER],
|
264
|
+
HEADER_CONST[:HMAP_HEADER_VERSION], 0, strings_offset, entries, num_buckets, 0)
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cocoapods'
|
4
|
+
|
5
|
+
module HMap
|
6
|
+
# mapfile dir name
|
7
|
+
# @api private
|
8
|
+
HMAP_DIR = 'HMap'
|
9
|
+
# mapfile type
|
10
|
+
# @note public => pods public,
|
11
|
+
# private => pods private,
|
12
|
+
# all => public + private + extra.
|
13
|
+
# @api private
|
14
|
+
HMMAP_TYPE = {
|
15
|
+
public_header_files: 'public',
|
16
|
+
private_header_files: 'private',
|
17
|
+
source_files: 'all'
|
18
|
+
}.freeze
|
19
|
+
|
20
|
+
# build setting HEAD_SEARCH_PATHs
|
21
|
+
HEAD_SEARCH_PATHS = 'HEADER_SEARCH_PATHS'
|
22
|
+
# Helper module which returns handle method from MapFileWriter.
|
23
|
+
class MapFileWriter
|
24
|
+
# @param save_origin_header_search_paths save_origin_header_search_paths
|
25
|
+
# @param clean_hmap clean up all hmap setup
|
26
|
+
def initialize(save_origin_header_search_paths, clean_hmap)
|
27
|
+
config = Pod::Config.instance
|
28
|
+
analyze = Helper::Pods.pod_analyze(config)
|
29
|
+
hmap_dir = hmap_dir(config)
|
30
|
+
targets = analyze.targets
|
31
|
+
pod_targets = analyze.pod_targets
|
32
|
+
clean_hmap(clean_hmap, hmap_dir, targets, pod_targets)
|
33
|
+
return if clean_hmap
|
34
|
+
|
35
|
+
@save_origin_header_search_paths = save_origin_header_search_paths
|
36
|
+
gen_mapfile(targets, pod_targets, hmap_dir)
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def hmap_dir(config)
|
42
|
+
puts "Current podfile dir: #{config.installation_root}"
|
43
|
+
hmap_dir = File.join(config.sandbox.headers_root, HMAP_DIR)
|
44
|
+
puts "Current HMap dir: #{hmap_dir}"
|
45
|
+
hmap_dir
|
46
|
+
end
|
47
|
+
|
48
|
+
def clean_hmap(clean_hmap, hmap_dir, *targets)
|
49
|
+
return unless clean_hmap
|
50
|
+
|
51
|
+
FileUtils.rm_rf(hmap_dir)
|
52
|
+
targets.each do |tg|
|
53
|
+
Utils.clean_target_build_setting(tg, HEAD_SEARCH_PATHS)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def gen_mapfile(targets, pod_targets, hmap_d)
|
58
|
+
puts('Inspecting targets to integrate ')
|
59
|
+
merge_all_pods_target_headers_mapfile(pod_targets, hmap_d)
|
60
|
+
merge_all_target_public_mapfile(targets, hmap_d)
|
61
|
+
create_each_target_mapfile(pod_targets, hmap_d)
|
62
|
+
end
|
63
|
+
|
64
|
+
def from_header_mappings_by_file_accessor(header_h, buckets, target, hmap_type)
|
65
|
+
hmap_s = 'headers'
|
66
|
+
hmap_s = "#{HMMAP_TYPE[hmap_type]}_#{hmap_s}" unless hmap_type == :source_files
|
67
|
+
headers = target.header_mappings_by_file_accessor.keys.flat_map(&hmap_s.to_sym)
|
68
|
+
s_headers = Helper::Pods.pod_target_source_header_map(target, hmap_type)
|
69
|
+
headers.each_with_object(buckets) do |header_f, sum|
|
70
|
+
keys = header_perfix(target, header_f, s_headers)
|
71
|
+
sum[0] += header_to_hash(keys, header_h, sum[0].length, sum[1])
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def header_perfix(target, file, s_headers)
|
76
|
+
key = file.basename.to_s
|
77
|
+
project_name = "#{target.project_name}/#{file.basename}"
|
78
|
+
product_module_name = "#{target.product_module_name}/#{file.basename}"
|
79
|
+
perfix = "#{file.dirname}/"
|
80
|
+
keys = [key, project_name, product_module_name] + (s_headers[key].nil? ? [] : s_headers[key])
|
81
|
+
keys.compact.uniq.inject([]) do |sum, name|
|
82
|
+
sum << [name, perfix, key]
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def header_to_hash(keys, headers, index, buckets)
|
87
|
+
keys.inject('') do |sum, bucket|
|
88
|
+
buckte = HMapBucketStr.new(*bucket)
|
89
|
+
string_t = buckte.bucket_to_string(headers, index + sum.length)
|
90
|
+
buckets.push(buckte)
|
91
|
+
sum + string_t
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def merge_all_target_public_mapfile(targets, hmap_dir)
|
96
|
+
method = method(:from_header_mappings_by_file_accessor)
|
97
|
+
targets.each do |target|
|
98
|
+
hmap_name = "All-Pods-Public-#{target.name}-hmap.hmap"
|
99
|
+
single_target_mapfile(target.pod_targets, hmap_dir, hmap_name, method)
|
100
|
+
change_target_xcconfig_header_search_path([hmap_name], true, *targets)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def merge_all_pods_target_headers_mapfile(pod_targets, hmap_dir)
|
105
|
+
method = method(:from_header_mappings_by_file_accessor)
|
106
|
+
hmap_name = 'All-Pods-All-Header-hmap.hmap'
|
107
|
+
single_target_mapfile(pod_targets, hmap_dir, hmap_name, method, :source_files)
|
108
|
+
change_target_xcconfig_header_search_path([hmap_name], true, *pod_targets)
|
109
|
+
end
|
110
|
+
|
111
|
+
def create_each_target_mapfile(pod_targets, hmap_dir)
|
112
|
+
pod_targets.each do |target|
|
113
|
+
HMMAP_TYPE.flat_map do |key, value|
|
114
|
+
hmap_name = "#{target.name}-#{value}-hmap.hmap"
|
115
|
+
method = method(:from_header_mappings_by_file_accessor)
|
116
|
+
single_target_mapfile([target], File.join(hmap_dir, target.name), hmap_name, method, key)
|
117
|
+
"#{target.name}/#{hmap_name}" if key == :source_files
|
118
|
+
end.compact
|
119
|
+
# change_target_xcconfig_header_search_path(hmap_h, false, target)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def single_target_mapfile(pod_targets, hmap_dir, hmap_name, headers, hmap_type = :public_header_files)
|
124
|
+
hmap_path = Pathname(File.join(hmap_dir, hmap_name))
|
125
|
+
header_h = {}
|
126
|
+
buckets = pod_targets.inject(["\0", []]) do |bucktes, target|
|
127
|
+
headers.call(header_h, bucktes, target, hmap_type)
|
128
|
+
end
|
129
|
+
wirte_mapfile_to_path(hmap_path, buckets)
|
130
|
+
end
|
131
|
+
|
132
|
+
def wirte_mapfile_to_path(hmap_path, buckets)
|
133
|
+
print "\t - save hmap file to path:"
|
134
|
+
puts hmap_path.to_s.yellow
|
135
|
+
MapFile.new(*buckets).write(hmap_path)
|
136
|
+
end
|
137
|
+
|
138
|
+
def change_target_xcconfig_header_search_path(hmap_h, use_headermap, *targets)
|
139
|
+
Utils.target_xcconfig_path(targets) do |xc|
|
140
|
+
Utils.chang_xcconfig_header_search_path(xc, hmap_h, use_headermap: use_headermap,
|
141
|
+
save_origin: @save_origin_header_search_paths)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module HMap
|
4
|
+
# hmap file writer
|
5
|
+
class MapFile
|
6
|
+
# @return mapfile string_table
|
7
|
+
attr_reader :string_table
|
8
|
+
|
9
|
+
# @return [Array<HMap::HMapBucketStr>] an array of the file's bucktes
|
10
|
+
# @note bucktes are provided in order of ascending offset.
|
11
|
+
attr_reader :buckets
|
12
|
+
|
13
|
+
# @api private
|
14
|
+
def initialize(strings, buckets)
|
15
|
+
@string_table = strings
|
16
|
+
@buckets = buckets
|
17
|
+
@map_data = HMapData.new(buckets)
|
18
|
+
end
|
19
|
+
|
20
|
+
# @return [String] the serialized fields of the mafile
|
21
|
+
def serialize
|
22
|
+
@map_data.serialize + @string_table
|
23
|
+
end
|
24
|
+
|
25
|
+
# Write all mafile data to the given filename.
|
26
|
+
# @param filename [String] the file to write to
|
27
|
+
# @return [void]
|
28
|
+
def write(path)
|
29
|
+
contents = serialize
|
30
|
+
Utils.update_changed_file(path, contents)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cocoapods'
|
4
|
+
|
5
|
+
module HMap
|
6
|
+
# A collection of Helper functions used throughout cocoapods-hmap.
|
7
|
+
module Helper
|
8
|
+
# A collection of Pods Helper functions used throughout cocoapods-hmap.
|
9
|
+
module Pods
|
10
|
+
HEADER_EXTENSIONS = Pod::Sandbox::FileAccessor::HEADER_EXTENSIONS
|
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.pod_target_source_header(target, hmap_t)
|
42
|
+
target.header_mappings_by_file_accessor.keys.flat_map do |key|
|
43
|
+
paths_for_attribute(key, hmap_t)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.pod_target_source_header_map(target, hmap_t)
|
48
|
+
pod_target_source_header(target, hmap_t).each_with_object({}) do |f, sum|
|
49
|
+
file = f[1]
|
50
|
+
key = f[0].to_s
|
51
|
+
r_key = file.basename.to_s
|
52
|
+
sum[r_key] = [key, r_key].uniq
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cocoapods'
|
4
|
+
|
5
|
+
module HMap
|
6
|
+
# A collection of utility functions used throughout cocoapods-hmap.
|
7
|
+
module Utils
|
8
|
+
HEADER_EXTENSIONS = Pod::Sandbox::FileAccessor::HEADER_EXTENSIONS
|
9
|
+
|
10
|
+
def self.index_of_range(num, range)
|
11
|
+
num &= range - 1
|
12
|
+
num
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.power_of_two?(num)
|
16
|
+
num != 0 && (num & (num - 1)).zero?
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.next_power_of_two(num)
|
20
|
+
num |= (num >> 1)
|
21
|
+
num |= (num >> 2)
|
22
|
+
num |= (num >> 4)
|
23
|
+
num |= (num >> 8)
|
24
|
+
num |= (num >> 16)
|
25
|
+
num |= (num >> 32)
|
26
|
+
num + 1
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.hash_set_value(hash, *args)
|
30
|
+
args.each do |arg|
|
31
|
+
hash.merge(arg)
|
32
|
+
end
|
33
|
+
hash
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.specialize_format(format, swapped)
|
37
|
+
modifier = swapped ? '<' : '>'
|
38
|
+
format.tr('=', modifier)
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.string_downcase_hash(str)
|
42
|
+
str.downcase.bytes.inject(0) do |sum, value|
|
43
|
+
sum += value * 13
|
44
|
+
sum
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.update_changed_file(path, contents)
|
49
|
+
if path.exist?
|
50
|
+
content_stream = StringIO.new(contents)
|
51
|
+
identical = File.open(path, 'rb') { |f| FileUtils.compare_stream(f, content_stream) }
|
52
|
+
return if identical
|
53
|
+
end
|
54
|
+
path.dirname.mkpath
|
55
|
+
File.open(path, 'w') { |f| f.write(contents) }
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.swapped_magic?(magic, version)
|
59
|
+
magic.eql?(HEADER_CONST[:HMAP_SWAPPED_MAGIC]) && version.eql?(HEADER_CONST[:HMAP_SWAPPED_VERSION])
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.magic?(magic)
|
63
|
+
magic.eql?(HEADER_CONST[:HMAP_SWAPPED_MAGIC]) || magic.eql?(HEADER_CONST[:HMAP_HEADER_MAGIC_NUMBER])
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.safe_encode(string, target_encoding)
|
67
|
+
string.encode(target_encoding)
|
68
|
+
rescue Encoding::InvalidByteSequenceError
|
69
|
+
string.force_encoding(target_encoding)
|
70
|
+
rescue Encoding::UndefinedConversionError
|
71
|
+
string.encode(target_encoding, fallback: lambda { |c|
|
72
|
+
c.force_encoding(target_encoding)
|
73
|
+
})
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.clean_target_build_setting(targets, build_setting)
|
77
|
+
target_xcconfig_path(targets) do |xc|
|
78
|
+
clean_build_setting_to_xcconfig(xc, build_setting)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.target_xcconfig_path(targets)
|
83
|
+
targets.each do |target|
|
84
|
+
raise ClassIncludedError.new(target.class, Pod::Target) unless target.is_a?(Pod::Target)
|
85
|
+
|
86
|
+
config_h = Pod::Target.instance_method(:build_settings).bind(target).call
|
87
|
+
config_h.each_key do |configuration_name|
|
88
|
+
xcconfig = target.xcconfig_path(configuration_name)
|
89
|
+
yield(xcconfig) if block_given?
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.chang_xcconfig_header_search_path(xcconfig, hmap_h, use_headermap: true, save_origin: true)
|
95
|
+
hmap_header_serach_paths = hmap_h.inject('') do |sum, hmap_n|
|
96
|
+
hmap_pod_root_path = "${PODS_ROOT}/Headers/#{HMAP_DIR}/#{hmap_n}"
|
97
|
+
sum + "\"#{hmap_pod_root_path}\" "
|
98
|
+
end
|
99
|
+
save_build_setting_to_xcconfig(xcconfig, hmap_header_serach_paths, HEAD_SEARCH_PATHS,
|
100
|
+
save_origin: save_origin) do |xc|
|
101
|
+
xc.attributes['USE_HEADERMAP'] = 'NO' unless use_headermap
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.save_build_setting_to_xcconfig(path, value, build_setting, save_origin: true)
|
106
|
+
xc = Xcodeproj::Config.new(path)
|
107
|
+
save_origin_build_setting = "SAVE_#{build_setting}"
|
108
|
+
hmap_build_setting = "HMAP_PODS_#{build_setting}"
|
109
|
+
origin_build_setting = xc.attributes[build_setting]
|
110
|
+
unless !origin_build_setting.nil? && origin_build_setting.include?(hmap_build_setting)
|
111
|
+
xc.attributes[save_origin_build_setting] =
|
112
|
+
origin_build_setting
|
113
|
+
end
|
114
|
+
|
115
|
+
value = "#{value} ${#{save_origin_build_setting}}" if save_origin
|
116
|
+
xc.attributes[hmap_build_setting] = value
|
117
|
+
xc.attributes[build_setting] = "${#{hmap_build_setting}}"
|
118
|
+
yield(xc) if block_given?
|
119
|
+
xc.save_as(path)
|
120
|
+
end
|
121
|
+
|
122
|
+
def self.clean_build_setting_to_xcconfig(path, build_setting)
|
123
|
+
xc = Xcodeproj::Config.new(path)
|
124
|
+
save_origin_build_setting = "SAVE_#{build_setting}"
|
125
|
+
hmap_build_setting = "HMAP_PODS_#{build_setting}"
|
126
|
+
origin_build_setting = xc.attributes[save_origin_build_setting]
|
127
|
+
puts "\t -xcconfig path: #{path}"
|
128
|
+
if origin_build_setting.nil?
|
129
|
+
puts "\t don't have #{save_origin_build_setting} in xcconfig file.".red
|
130
|
+
return
|
131
|
+
end
|
132
|
+
xc.attributes[build_setting] = origin_build_setting
|
133
|
+
xc.attributes.delete(save_origin_build_setting)
|
134
|
+
xc.attributes.delete(hmap_build_setting)
|
135
|
+
xc.attributes['USE_HEADERMAP'] = 'YES'
|
136
|
+
xc.save_as(path)
|
137
|
+
puts "\t clean finish."
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module HMap
|
4
|
+
# A representation of some unspecified hmap data.
|
5
|
+
class HMapView
|
6
|
+
# @return [String] the raw hmap data
|
7
|
+
attr_reader :raw_data
|
8
|
+
|
9
|
+
# @return [Symbol] the endianness of the data (`:big` or `:little`)
|
10
|
+
attr_reader :endianness
|
11
|
+
|
12
|
+
# @return [Integer] the offset of the relevant data (in {#raw_data})
|
13
|
+
attr_reader :offset
|
14
|
+
|
15
|
+
# Creates a new HMapView.
|
16
|
+
# @param raw_data [String] the raw hmap data
|
17
|
+
# @param endianness [Symbol] the endianness of the data
|
18
|
+
# @param offset [Integer] the offset of the relevant data
|
19
|
+
def initialize(raw_data, endianness, offset)
|
20
|
+
@raw_data = raw_data
|
21
|
+
@endianness = endianness
|
22
|
+
@offset = offset
|
23
|
+
end
|
24
|
+
|
25
|
+
# @return [Hash] a hash representation of this {HMapView}.
|
26
|
+
def to_h
|
27
|
+
{
|
28
|
+
'endianness' => endianness,
|
29
|
+
'offset' => offset
|
30
|
+
}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The primary namespace for cocoapods-hmap.
|
4
|
+
module HMap
|
5
|
+
require_relative 'cocoapods-hmap/version'
|
6
|
+
require_relative 'cocoapods-hmap/view'
|
7
|
+
require_relative 'cocoapods-hmap/hmap_struct'
|
8
|
+
require_relative 'cocoapods-hmap/utils'
|
9
|
+
require_relative 'cocoapods-hmap/pods_helper'
|
10
|
+
require_relative 'cocoapods-hmap/exceptions'
|
11
|
+
|
12
|
+
autoload :MapFileReader, 'cocoapods-hmap/hmap_reader'
|
13
|
+
autoload :MapFileWriter, 'cocoapods-hmap/hmap_writer'
|
14
|
+
autoload :MapFile, 'cocoapods-hmap/mapfile'
|
15
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cocoapods-hmap/command/hmap_gen'
|
4
|
+
require 'cocoapods-hmap/command/hmap_reader'
|
5
|
+
|
6
|
+
module Pod
|
7
|
+
# hook
|
8
|
+
module CocoaPodsHMapHook
|
9
|
+
HooksManager.register('cocoapods-mapfile', :post_install) do
|
10
|
+
Command::HMapGen.run(["--project-directory=#{Config.instance.installation_root}", "--nosave-origin-header-search-paths"])
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
metadata
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cocoapods-mapfile
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.6
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Cat1237
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-07-06 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: header_reader lets your read Xcode header map file. header-writer lets
|
84
|
+
your analyze the project pod dependencies and gen header map file for all pods.
|
85
|
+
email:
|
86
|
+
- wangson1237@outlook.com
|
87
|
+
executables:
|
88
|
+
- hmap_reader
|
89
|
+
- hmap_writer
|
90
|
+
extensions: []
|
91
|
+
extra_rdoc_files: []
|
92
|
+
files:
|
93
|
+
- LICENSE
|
94
|
+
- README.md
|
95
|
+
- bin/hmap_reader
|
96
|
+
- bin/hmap_writer
|
97
|
+
- lib/cocoapods-hmap/command/hmap_gen.rb
|
98
|
+
- lib/cocoapods-hmap/command/hmap_reader.rb
|
99
|
+
- lib/cocoapods-hmap/exceptions.rb
|
100
|
+
- lib/cocoapods-hmap/hmap_reader.rb
|
101
|
+
- lib/cocoapods-hmap/hmap_struct.rb
|
102
|
+
- lib/cocoapods-hmap/hmap_writer.rb
|
103
|
+
- lib/cocoapods-hmap/mapfile.rb
|
104
|
+
- lib/cocoapods-hmap/pods_helper.rb
|
105
|
+
- lib/cocoapods-hmap/utils.rb
|
106
|
+
- lib/cocoapods-hmap/version.rb
|
107
|
+
- lib/cocoapods-hmap/view.rb
|
108
|
+
- lib/cocoapods_hmap.rb
|
109
|
+
- lib/cocoapods_plugin.rb
|
110
|
+
homepage: https://github.com/Cat1237/cocoapods-hmap.git
|
111
|
+
licenses:
|
112
|
+
- MIT
|
113
|
+
metadata: {}
|
114
|
+
post_install_message:
|
115
|
+
rdoc_options: []
|
116
|
+
require_paths:
|
117
|
+
- lib
|
118
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
119
|
+
requirements:
|
120
|
+
- - ">="
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '2.5'
|
123
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
124
|
+
requirements:
|
125
|
+
- - ">="
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
version: '0'
|
128
|
+
requirements: []
|
129
|
+
rubygems_version: 3.1.6
|
130
|
+
signing_key:
|
131
|
+
specification_version: 4
|
132
|
+
summary: Read or write header map file.
|
133
|
+
test_files: []
|