cocoapods-headermap 1.0.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 03773ea3588ccfd9fc4f5be042da14a89b41134922afa52c7eec230370014a06
4
+ data.tar.gz: b13fe6e18cf5571eefdc4314bccd88106d39442fcbaded7906a1e7c2690b5a03
5
+ SHA512:
6
+ metadata.gz: 9ade511448e2ab9b3d380604a1114ab9eb36120847ad2f37867102297cdf06589580e148f528b1df177c9f5700053372735f005c7adc52fa09e416e73d9670bc
7
+ data.tar.gz: eee532c7e86bfb62dcb4fc0839e077c23e3546d9d100c9f5174277ec495c25d498750d4661cd9190539bee5509943bc86a09d4fafbd3bac5fd07b32b5013f435
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ .DS_Store
2
+ pkg
3
+ .idea/
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in cocoapods-headermap.gemspec
4
+ gemspec
5
+
6
+ group :development do
7
+ gem 'cocoapods'
8
+
9
+ gem 'mocha'
10
+ gem 'bacon'
11
+ gem 'mocha-on-bacon'
12
+ gem 'prettybacon'
13
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2021 menttofly <1028365614@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,13 @@
1
+ # cocoapods-headermap
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/cocoapods-headermap.svg)](https://badge.fury.io/rb/cocoapods-headermap)
4
+
5
+ A description of cocoapods-headermap.
6
+
7
+ ## Installation
8
+
9
+ $ gem install cocoapods-headermap
10
+
11
+ ## Usage
12
+
13
+ $ pod spec headermap POD_NAME
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ def specs(dir)
4
+ FileList["spec/#{dir}/*_spec.rb"].shuffle.join(' ')
5
+ end
6
+
7
+ desc 'Runs all the specs'
8
+ task :specs do
9
+ sh "bundle exec bacon #{specs('**')}"
10
+ end
11
+
12
+ task :default => :specs
13
+
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'cocoapods-headermap/gem_version.rb'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'cocoapods-headermap'
8
+ spec.version = CocoapodsHeadermap::VERSION
9
+ spec.authors = ['menttofly']
10
+ spec.email = ['1028365614@qq.com']
11
+ spec.description = %q{Improve Xcode compilation speed based on Header Maps.}
12
+ spec.summary = %q{Generate header maps file instead of creating soft link during pod installation. Therefore, file IO can be reduced during the build process and the search speed of header files can be improved.}
13
+ spec.homepage = 'https://github.com/'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_development_dependency 'bundler', '~> 1.3'
22
+ spec.add_development_dependency 'rake'
23
+ end
@@ -0,0 +1,63 @@
1
+ require 'cocoapods-headermap/headers_store'
2
+
3
+ module Pod
4
+ class Target
5
+ class BuildSettings
6
+ class PodTargetSettings < BuildSettings
7
+
8
+ # Call `define_build_settings_method` with a given block in order to disable sorting.
9
+ define_build_settings_method :header_search_paths, :build_setting => true, :memoized => true, :sorted => false do
10
+ paths = target.header_search_paths(:include_dependent_targets_for_test_spec => test_xcconfig? && non_library_spec, :include_dependent_targets_for_app_spec => app_xcconfig? && non_library_spec, :configuration => @configuration)
11
+
12
+ dependent_vendored_xcframeworks = []
13
+ dependent_vendored_xcframeworks.concat vendored_xcframeworks
14
+ dependent_vendored_xcframeworks.concat dependent_targets.flat_map { |pt| pt.build_settings[@configuration].vendored_xcframeworks }
15
+ paths.concat dependent_vendored_xcframeworks.
16
+ select { |xcf| xcf.build_type.static_library? }.
17
+ map { |xcf| "#{BuildSettings.xcframework_intermediate_dir(xcf)}/Headers" }.
18
+ compact
19
+ paths
20
+ end
21
+
22
+ # @return [Array<String>] The path of `hmap` file for this project
23
+ define_build_settings_method :user_header_search_paths, :build_setting => true, :memoized => true, :sorted => false do
24
+ paths = ["${PODS_ROOT}/#{target.sandbox.headers_root.basename}/#{Sandbox::POD_PROJECT_HEADERS}.hmap"]
25
+ paths
26
+ end
27
+ end
28
+
29
+ class AggregateTargetSettings < BuildSettings
30
+ # # Call `define_build_settings_method` with a given block in order to disable sorting paths.
31
+ define_build_settings_method :header_search_paths, :build_setting => true, :memoized => true, :sorted => false, :uniqued => true do
32
+ paths = []
33
+
34
+ if !target.build_as_framework? || !pod_targets.all?(&:should_build?)
35
+ paths.concat target.sandbox.public_headers.search_paths(target.platform)
36
+ end
37
+
38
+ # Make frameworks headers discoverable with any syntax (quotes,
39
+ # brackets, @import, etc.)
40
+ paths.concat pod_targets.
41
+ select { |pt| pt.build_as_framework? && pt.should_build? }.
42
+ map { |pt| pt.build_settings[@configuration].framework_header_search_path }
43
+
44
+ xcframework_library_headers = pod_targets.flat_map { |pt| pt.build_settings[@configuration].vendored_xcframeworks }.
45
+ select { |xcf| xcf.build_type.static_library? }.
46
+ map { |xcf| "#{BuildSettings.xcframework_intermediate_dir(xcf)}/Headers" }.
47
+ compact
48
+
49
+ paths.concat xcframework_library_headers
50
+ paths.concat target.search_paths_aggregate_targets.flat_map { |at| at.build_settings(configuration_name).header_search_paths }
51
+ paths
52
+ end
53
+
54
+ # @return [Array<String>] The path of `hmap` file for this project
55
+ define_build_settings_method :user_header_search_paths, :build_setting => true, :memoized => true, :sorted => false do
56
+ paths = ["${PODS_ROOT}/#{target.sandbox.headers_root.basename}/#{Sandbox::POD_PROJECT_HEADERS}.hmap"]
57
+ paths
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+
@@ -0,0 +1,44 @@
1
+ module Pod
2
+ class Command
3
+ # This is an example of a cocoapods plugin adding a top-level subcommand
4
+ # to the 'pod' command.
5
+ #
6
+ # You can also create subcommands of existing or new commands. Say you
7
+ # wanted to add a subcommand to `list` to show newly deprecated pods,
8
+ # (e.g. `pod list deprecated`), there are a few things that would need
9
+ # to change.
10
+ #
11
+ # - move this file to `lib/pod/command/list/deprecated.rb` and update
12
+ # the class to exist in the the Pod::Command::List namespace
13
+ # - change this class to extend from `List` instead of `Command`. This
14
+ # tells the plugin system that it is a subcommand of `list`.
15
+ # - edit `lib/cocoapods_plugins.rb` to require this file
16
+ #
17
+ # @todo Create a PR to add your plugin to CocoaPods/cocoapods.org
18
+ # in the `plugins.json` file, once your plugin is released.
19
+ #
20
+ class Headermap < Command
21
+ self.summary = 'Short description of cocoapods-headermap.'
22
+
23
+ self.description = <<-DESC
24
+ Longer description of cocoapods-headermap.
25
+ DESC
26
+
27
+ self.arguments = 'NAME'
28
+
29
+ def initialize(argv)
30
+ @name = argv.shift_argument
31
+ super
32
+ end
33
+
34
+ def validate!
35
+ super
36
+ help! 'A Pod name is required.' unless @name
37
+ end
38
+
39
+ def run
40
+ UI.puts "Add your implementation for the cocoapods-headermap plugin in #{__FILE__}"
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1 @@
1
+ require 'cocoapods-headermap/command/headermap'
@@ -0,0 +1,36 @@
1
+ module Pod
2
+ class Configuration
3
+ # 保存 `$PODS_ROOT/Headers` 目录下所有 Header Search Paths
4
+ # 始终保留头文件 symlink!!!
5
+ # 默认为 false
6
+ @keep_symlink_headers = false
7
+
8
+ # 始终保留 symlink & Header Search Paths 的组件
9
+ # 在 keep_symlink_headers 为 false 时有效
10
+ @always_keep_symlink_headers = []
11
+
12
+ # Multi Pods Project 是否生成 Single Pods Target 不带命名空间的 headers 全集
13
+ # 默认为 false(暂时无效)
14
+ @use_legacy_project_headers = false
15
+
16
+ class << self
17
+ attr_reader :keep_symlink_headers
18
+ def keep_symlink_headers=(keep_symlink_headers)
19
+ raise Informative, "[cocoapods-headermap]: Expecting Boolean type for `:keep_symlink_headers`!" unless [true, false].include?(keep_symlink_headers)
20
+ @keep_symlink_headers = keep_symlink_headers
21
+ end
22
+
23
+ attr_reader :always_keep_symlink_headers
24
+ def always_keep_symlink_headers=(always_keep_symlink_headers)
25
+ raise Informative, "[cocoapods-headermap]: Expecting array type for `:always_keep_symlink_headers`!" unless always_keep_symlink_headers.is_a?(Array)
26
+ @always_keep_symlink_headers.concat always_keep_symlink_headers
27
+ end
28
+
29
+ attr_reader :use_legacy_project_headers
30
+ def use_legacy_project_headers=(use_legacy_project_headers)
31
+ raise Informative, "[cocoapods-headermap]: Expecting Boolean type for `:use_legacy_project_headers`!" unless [true, false].include?(use_legacy_project_headers)
32
+ @use_legacy_project_headers = use_legacy_project_headers
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,47 @@
1
+ require 'json'
2
+ require 'cocoapods-headermap/header_maps_generator'
3
+
4
+ module Pod
5
+ class Installer
6
+ class Xcode
7
+ class PodsProjectGenerator
8
+ class FileReferencesInstaller
9
+
10
+ def link_headers
11
+ UI.message '- Linking headers' do
12
+ pod_targets.each do |pod_target|
13
+ next if pod_target.build_as_framework? && pod_target.should_build?
14
+ sync_target_info(pod_target)
15
+ create_symlink_reference(pod_target)
16
+ HeaderMapsGenerator.merge_target_headers(pod_target)
17
+ end
18
+ end
19
+ end
20
+
21
+ def sync_target_info(pod_target)
22
+ # pod_target.build_headers.user_clang_module = true if pod_target.file_accessors.first.module_map
23
+ pod_target.build_headers.target_name = pod_target.pod_name
24
+ sandbox.public_headers.target_name = pod_target.pod_name
25
+ end
26
+
27
+ # Creates the link to the headers of the Pod in the sandbox.
28
+ def create_symlink_reference(pod_target)
29
+ pod_target_header_mappings = pod_target.header_mappings_by_file_accessor.values
30
+ pod_target_header_mappings.each do |header_mappings|
31
+ header_mappings.each do |namespaced_path, files|
32
+ pod_target.build_headers.add_files(namespaced_path, files)
33
+ end
34
+ end
35
+
36
+ public_header_mappings = pod_target.public_header_mappings_by_file_accessor.values
37
+ public_header_mappings.each do |header_mappings|
38
+ header_mappings.each do |namespaced_path, files|
39
+ sandbox.public_headers.add_files(namespaced_path, files)
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,3 @@
1
+ module CocoapodsHeadermap
2
+ VERSION = "1.0.7"
3
+ end
@@ -0,0 +1,168 @@
1
+ module Pod
2
+ class HeaderMapsGenerator
3
+
4
+ # 所有 target 共享的头文件信息,不带命名空间或路径
5
+ @all_project_headers = {}
6
+
7
+ # 所有 target 公共 header 信息,带命名空间或路径
8
+ @all_targets_headers = {}
9
+
10
+ # Maintains the headers cache for project.
11
+ @headers_cache = nil
12
+
13
+ # Record headers orgnized by target on order to adapt the situation of file change in some targets.
14
+ @project_headers_by_target = {}
15
+ @targets_headers_by_target = {}
16
+
17
+ # A set of pod target names that were deleted.
18
+ # Only use for `incremental_installation` enabled.
19
+ @deleted_pod_targets = Set.new
20
+
21
+ class << self
22
+ attr_accessor :all_project_headers, :all_targets_headers
23
+ attr_accessor :project_headers_by_target, :targets_headers_by_target
24
+ attr_accessor :headers_cache
25
+ attr_reader :deleted_pod_targets
26
+
27
+ def deleted_pod_targets=(deleted_pod_target)
28
+ return if deleted_pod_target.nil?
29
+ deleted_pod_targets << deleted_pod_target
30
+ end
31
+
32
+ # Generate header map files for all project and targets.
33
+ def generate!(sandbox, is_legacy_target)
34
+ UI.puts "[cocoapods-headermap]: Generating header maps.."
35
+ # 跨组件引用的 public header
36
+ generate_header_files(sandbox.headers_root, all_targets_headers, Sandbox::POD_TARGETS_HEADERS)
37
+ # 组件内部使用的 private header
38
+ project_headers_by_target.each do |target_name, project_headers|
39
+ generate_header_files(sandbox.headers_root + "Private/#{target_name}", project_headers, target_name)
40
+ end
41
+
42
+ # return if !is_legacy_target || !Configuration.use_legacy_project_headers
43
+ generate_header_files(sandbox.headers_root, all_project_headers, Sandbox::POD_PROJECT_HEADERS)
44
+ end
45
+
46
+ # Store headers cache to sandbox.
47
+ def store_cache_to(path)
48
+ return unless headers_cache
49
+ headers_cache.update_headers!(project_headers_by_target, targets_headers_by_target)
50
+ headers_cache.save_as(path)
51
+ end
52
+
53
+ # Fetch headers cache from sandbox if `incremental_installation` enabled.
54
+ def analyze_cache_from(path, regenerate_pod_targets)
55
+ UI.message 'Analyzing Headers Cache' do
56
+ self.headers_cache = HeaderMapsCache.from_file(path)
57
+ # Regenerate pod target must remove cache first.
58
+ unless regenerate_pod_targets.nil? || regenerate_pod_targets.empty?
59
+ regenerate_pod_targets.each do |pod_target|
60
+ headers_cache.project_headers_cache.delete(pod_target.pod_name)
61
+ headers_cache.targets_headers_cache.delete(pod_target.pod_name)
62
+ end
63
+ end
64
+
65
+ # Pods that were deleted need to be removed from cache.
66
+ unless deleted_pod_targets.empty?
67
+ deleted_pod_targets.each do |pod_name|
68
+ headers_cache.project_headers_cache.delete(pod_name)
69
+ headers_cache.targets_headers_cache.delete(pod_name)
70
+ end
71
+ end
72
+
73
+ self.project_headers_by_target = headers_cache.project_headers_cache
74
+ self.targets_headers_by_target = headers_cache.targets_headers_cache
75
+
76
+ # 将恢复的缓存和当前重新生成的 target 合并
77
+ project_headers_by_target.each do |pod_target, project_headers|
78
+ all_project_headers.merge!(project_headers) { |key, pre, new| pre } unless project_headers.empty?
79
+ end
80
+ targets_headers_by_target.each do |pod_target, targets_headers|
81
+ all_targets_headers.merge!(targets_headers) unless targets_headers.empty?
82
+ end
83
+ end
84
+ end
85
+
86
+ # Merge the headers for every target and the whole project.
87
+ # If there is a header file with the same name between different pods, it will keep the previous one.
88
+ def merge_target_headers(pod_target)
89
+ pod_project_headers = pod_target.build_headers.pod_project_headers
90
+ all_project_headers.merge!(pod_project_headers) { |key, pre, new| pre } unless pod_project_headers.empty?
91
+
92
+ pod_target_headers = pod_target.build_headers.pod_target_headers
93
+ all_targets_headers.merge!(pod_target_headers) unless pod_target_headers.empty?
94
+
95
+ # Store original data structure of header ordered by target.
96
+ project_headers_by_target[pod_target.pod_name] = pod_project_headers unless pod_project_headers.empty?
97
+ targets_headers_by_target[pod_target.pod_name] = pod_target_headers unless pod_target_headers.empty?
98
+ end
99
+
100
+ # Generate `hmap` files for the project of `Pods`.
101
+ # Pods-all-target-headers.hmap 作为组件 public hmap
102
+ # Pods-project-headers.hmap 作为不规范 import 组件的兼容 hmap
103
+ # target_name.hmap 作为组件 private hmap
104
+ def generate_header_files(dirname, headers, file_name)
105
+ return if headers.nil? || headers.empty?
106
+
107
+ header_json_path = dirname + "#{file_name}.json"
108
+ File.open(header_json_path, "w") do |f|
109
+ f.write(JSON.pretty_generate(headers))
110
+ end
111
+ json_to_hmap(header_json_path)
112
+ end
113
+
114
+ # Convert json file to headermap file.
115
+ def json_to_hmap(json_path)
116
+ install_brew_package(1) if `which hmap`.empty?
117
+
118
+ hmap_path = json_path.sub_ext(".hmap")
119
+ `hmap convert #{json_path} #{hmap_path}`
120
+
121
+ File.delete(json_path) if File.exist?(json_path)
122
+ end
123
+
124
+ # Install swift headermap tool less than three times if neccessary.
125
+ def install_brew_package(retry_count)
126
+ raise Informative, "[cocoapods-headermap]: Excuting `brew install milend/taps/hmap` error!" if retry_count > 3
127
+ if_install_success = system "brew install milend/taps/hmap"
128
+ install_brew_package(retry_count + 1) unless if_install_success
129
+ end
130
+ end
131
+ end
132
+
133
+ # Cache header maps content for `incremental_installation` option
134
+ class HeaderMapsCache
135
+ attr_reader :project_headers_cache, :targets_headers_cache
136
+
137
+ def initialize(project_headers_cache = {}, targets_headers_cache = {})
138
+ @project_headers_cache = project_headers_cache
139
+ @targets_headers_cache = targets_headers_cache
140
+ end
141
+
142
+ def self.from_file(path)
143
+ return HeaderMapsCache.new unless File.exist?(path)
144
+
145
+ yaml_content = YAMLHelper.load_file(path)
146
+ project_headers_cache = yaml_content.fetch("PROJECT_HEADERS", {})
147
+ targets_headers_cache = yaml_content.fetch("TARGETS_HEADERS", {})
148
+ new(project_headers_cache, targets_headers_cache)
149
+ end
150
+
151
+ def update_headers!(project_headers_by_target, targets_headers_by_target)
152
+ @project_headers_cache = project_headers_by_target
153
+ @targets_headers_cache = targets_headers_by_target
154
+ end
155
+
156
+ def to_hash
157
+ yaml_content = {}
158
+ yaml_content["PROJECT_HEADERS"] = project_headers_cache if project_headers_cache
159
+ yaml_content["TARGETS_HEADERS"] = targets_headers_cache if targets_headers_cache
160
+ yaml_content
161
+ end
162
+
163
+ def save_as(path)
164
+ Pathname(path).dirname.mkpath
165
+ Sandbox.update_changed_file(path, YAMLHelper.convert(to_hash))
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,128 @@
1
+ require 'fileutils'
2
+ require 'cocoapods-headermap/configuration'
3
+
4
+ module Pod
5
+ class Sandbox
6
+ POD_TARGETS_HEADERS = "Pods-all-target-headers"
7
+ POD_PROJECT_HEADERS = "Legacy-project-headers"
8
+
9
+ class HeadersStore
10
+ # Implememt the effect of tuples.
11
+ SYMLINK_REFERENCE = Struct.new(:namespace, :relative_header_path)
12
+
13
+ alias_method :new_add_files, :add_files
14
+ alias_method :new_search_paths, :search_paths
15
+
16
+ # 保存当前 target name
17
+ attr_reader :target_name
18
+ def target_name=(target_name)
19
+ @target_name = target_name
20
+ end
21
+
22
+ # @return [Hash{Pathname => Hash{String, String}}] public headers 映射
23
+ def pod_target_headers
24
+ @pod_target_headers ||= {}
25
+ end
26
+
27
+ # @return [Hash{Pathname => Hash{String, String}}] private headers 映射
28
+ def pod_project_headers
29
+ @pod_project_headers ||= {}
30
+ end
31
+
32
+ # @return [Array<Pathname>] Generate every part of namespace recusively.
33
+ # Passing ["WCDB", "include", "source"] return the following content:
34
+ #
35
+ # ["WCDB/include/source", "include/source", "source"]
36
+ def purge_shared_keys(parts, index)
37
+ return [] if index == parts.length
38
+ res = [parts.slice(index, parts.length - index).reduce(Pathname.new(""), :+)]
39
+ res.concat(purge_shared_keys(parts, index + 1))
40
+ res
41
+ end
42
+
43
+ def add_files(namespace, relative_header_paths)
44
+ root.join(namespace).mkpath unless relative_header_paths.empty?
45
+
46
+ new_add_files(namespace, relative_header_paths)
47
+ return if @visibility_scope == :public
48
+
49
+ list = namespace.each_filename.to_a
50
+ parts = purge_shared_keys(list, 0)
51
+ relative_header_paths.map do |relative_header_path|
52
+ add_targets_headers(parts, namespace, relative_header_path)
53
+ add_project_headers(relative_header_path)
54
+ end
55
+ end
56
+
57
+ # 保存带命名空间的 headers 与其 symlink 路径的映射
58
+ # 结构如下:
59
+ # {"AFNetworking/AFNetworking.h" => "$PODS_ROOT/Headers/Public/AFNetworking/AFNetworking.h"}
60
+ #
61
+ # 用于生成 public hmap,并写入 `HEADER_SEARCH_PATH`,可使用 <Pod/header.h>、"Pod/head.h" 引用
62
+ # 如果 `namespace/header` 字典序更大,将覆盖之前的 path 值
63
+ def add_targets_headers(parts, namespace, relative_header_path)
64
+
65
+ # public header,使用头文件 symlink 路径
66
+ header_source = root + namespace + relative_header_path.basename
67
+ header_section = {
68
+ "prefix" => "#{header_source.dirname.to_s}/",
69
+ "suffix" => header_source.basename.to_s
70
+ }
71
+
72
+ parts.each do |part|
73
+ key = "#{part}/#{header_source.basename}"
74
+ next if pod_target_headers.key?(key) && (pod_target_headers[key]["prefix"] <=> "#{header_source.dirname.to_s}/") == 1
75
+ pod_target_headers[key] = header_section
76
+ end
77
+ end
78
+
79
+ # 保存不带命名空间的 header 与其原始路径的映射
80
+ # 结构如下:
81
+ #
82
+ # {"AFNetworking" => "$PODS_ROOT/AFNetworking/AFNetworking.h"}
83
+ #
84
+ # 用于生成 private hmap,并写入 `HEADER_SEARCH_PATH`,在组件内部 *.{m,c,cpp} 使用 <header.h>、"head.h" 引用
85
+ # 可选生成跨组件的 shared hmap,写入 `USER_HEADER_SEARCH_PATH`,规避不规范 un-namespaced 引用
86
+ def add_project_headers(relative_header_path)
87
+
88
+ # private header,使用头文件原始路径
89
+ header_source = sandbox.root + relative_header_path
90
+
91
+ source_file_name = header_source.basename.to_s
92
+ header_section = {
93
+ "prefix" => "#{header_source.dirname.to_s}/",
94
+ "suffix" => source_file_name.to_s
95
+ }
96
+
97
+ return if pod_project_headers.key?(source_file_name) && (pod_project_headers[source_file_name]["prefix"] <=> "#{header_source.dirname.to_s}/") == 1
98
+ pod_project_headers[source_file_name] = header_section
99
+ end
100
+
101
+ # @return [Array<String>] Public hmap + Private hmap
102
+ def search_paths(platform, target_name = nil, use_modular_headers = false)
103
+ visibility_dir = root.relative_path_from(sandbox.root)
104
+ headers_dir = visibility_dir.dirname
105
+
106
+ paths = []
107
+ paths << "${PODS_ROOT}/#{visibility_dir}/#{@target_name}/#{@target_name}.hmap" if @visibility_scope == :private
108
+ paths << "${PODS_ROOT}/#{headers_dir}/#{Sandbox::POD_TARGETS_HEADERS}.hmap"
109
+
110
+ # 保留 CocoaPods 自动写入的 symlink 路径
111
+ if Configuration.keep_symlink_headers
112
+ paths.concat(new_search_paths(platform, target_name, use_modular_headers))
113
+ else
114
+ if Configuration.always_keep_symlink_headers.include?(target_name)
115
+ paths.concat(new_search_paths(platform, target_name, use_modular_headers))
116
+ end
117
+ end
118
+ paths
119
+ end
120
+
121
+ # Clean `$PODS_ROOT/Headers` directory.
122
+ def rm_headers_root!
123
+ return if @visibility_scope == :private
124
+ FileUtils.rm_rf(Dir.glob(sandbox.headers_root + "**" + "*.hmap"))
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,31 @@
1
+ require 'cocoapods-headermap/configuration'
2
+
3
+ module Pod
4
+ class Installer
5
+ alias_method :new_run_podfile_post_install_hooks, :run_podfile_post_install_hooks
6
+ alias_method :new_clean_sandbox, :clean_sandbox
7
+
8
+ def run_podfile_post_install_hooks
9
+ # 开启 Multi Pods Project 选项
10
+ if podfile.installation_options.generate_multiple_pod_projects
11
+ @pod_target_subprojects.flat_map { |project| project.targets }.each do |target|
12
+ target.build_configurations.each do |config|
13
+ config.build_settings['USE_HEADERMAP'] = 'NO'
14
+ end
15
+ end
16
+ else
17
+ @pods_project.targets.each do |target|
18
+ target.build_configurations.each do |config|
19
+ config.build_settings['USE_HEADERMAP'] = 'NO'
20
+ end
21
+ end
22
+ end
23
+ new_run_podfile_post_install_hooks
24
+ end
25
+
26
+ def clean_sandbox(pod_targets)
27
+ new_clean_sandbox(pod_targets)
28
+ sandbox.public_headers.rm_headers_root!
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,46 @@
1
+ require 'cocoapods-headermap/header_maps_generator'
2
+
3
+ module Pod
4
+ class Installer
5
+ class Xcode
6
+ class MultiPodsProjectGenerator < PodsProjectGenerator
7
+ def generate!
8
+ # Generate container Pods.xcodeproj.
9
+ container_project = create_container_project(aggregate_targets, sandbox.project_path)
10
+
11
+ project_paths_by_pod_targets = pod_targets.group_by do |pod_target|
12
+ sandbox.pod_target_project_path(pod_target.project_name)
13
+ end
14
+
15
+ # If `incremental_installation` enabled, read cache from sanbox.
16
+ if installation_options.incremental_installation
17
+ HeaderMapsGenerator.analyze_cache_from(project_headers_cache_path, pod_targets)
18
+ end
19
+
20
+ projects_by_pod_targets = Hash[project_paths_by_pod_targets.map do |project_path, pod_targets|
21
+ project = create_pods_project(pod_targets, project_path, container_project)
22
+ [project, pod_targets]
23
+ end]
24
+
25
+ # Generate header map files and cache if neccessary.
26
+ HeaderMapsGenerator.generate!(sandbox, false)
27
+ HeaderMapsGenerator.store_cache_to(project_headers_cache_path)
28
+
29
+ # Note: We must call `install_file_references` on all pod targets before installing them.
30
+ pod_target_installation_results = install_all_pod_targets(projects_by_pod_targets)
31
+ aggregate_target_installation_results = install_aggregate_targets_into_project(container_project, aggregate_targets)
32
+ target_installation_results = InstallationResults.new(pod_target_installation_results, aggregate_target_installation_results)
33
+
34
+ integrate_targets(target_installation_results.pod_target_installation_results)
35
+ wire_target_dependencies(target_installation_results)
36
+ PodsProjectGeneratorResult.new(container_project, projects_by_pod_targets, target_installation_results)
37
+ end
38
+
39
+ # Project headers cache path.
40
+ def project_headers_cache_path
41
+ sandbox.root.join('.project_cache', 'project_headers_cache.yaml')
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,24 @@
1
+ module Pod
2
+ class PodTarget < Target
3
+ alias_method :new_header_search_paths, :header_search_paths
4
+
5
+ # Move the mapping files to the top of the array by sorting.
6
+ #
7
+ # Before sort:
8
+ # ["${PODS_ROOT}/Headers/Private/AFNetworking.hmap",
9
+ # "${PODS_ROOT}/Headers/Private/AFNetworking",
10
+ # "${PODS_ROOT}/Headers/Public/Public-Header-Maps.hmap",
11
+ # "${PODS_ROOT}/Headers/Public/AFNetworking"]
12
+ #
13
+ # After sort:
14
+ # ["${PODS_ROOT}/Headers/Private/AFNetworking.hmap",
15
+ # "${PODS_ROOT}/Headers/Public/Public-Header-Maps.hmap",
16
+ # "${PODS_ROOT}/Headers/Private/AFNetworking",
17
+ # "${PODS_ROOT}/Headers/Public/AFNetworking"]
18
+ def header_search_paths(include_dependent_targets_for_test_spec: nil, include_dependent_targets_for_app_spec: nil, include_private_headers: true, configuration: nil)
19
+ paths = new_header_search_paths(:include_dependent_targets_for_test_spec => include_dependent_targets_for_test_spec, :include_dependent_targets_for_app_spec => include_dependent_targets_for_app_spec, :include_private_headers => include_private_headers, :configuration => configuration)
20
+ paths.sort_by { |i| i.split(".").last == "hmap" ? 0 : 1 }
21
+ paths
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,12 @@
1
+ require 'cocoapods-headermap/header_maps_generator'
2
+
3
+ module Pod
4
+ class Sandbox
5
+ alias_method :new_clean_pod, :clean_pod
6
+
7
+ def clean_pod(name)
8
+ new_clean_pod(name)
9
+ HeaderMapsGenerator.deleted_pod_targets = name
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,29 @@
1
+ require 'cocoapods-headermap/header_maps_generator'
2
+
3
+ module Pod
4
+ class Installer
5
+ class Xcode
6
+ class SinglePodsProjectGenerator < PodsProjectGenerator
7
+ def generate!
8
+ project_path = sandbox.project_path
9
+ platforms = aggregate_targets.map(&:platform)
10
+ project_generator = ProjectGenerator.new(sandbox, project_path, pod_targets, build_configurations,
11
+ platforms, project_object_version, config.podfile_path)
12
+ project = project_generator.generate!
13
+ install_file_references(project, pod_targets)
14
+
15
+ # Generate header map files.
16
+ HeaderMapsGenerator.generate!(sandbox, true)
17
+
18
+ pod_target_installation_results = install_all_pod_targets(project, pod_targets)
19
+ aggregate_target_installation_results = install_aggregate_targets(project, aggregate_targets)
20
+ target_installation_results = InstallationResults.new(pod_target_installation_results, aggregate_target_installation_results)
21
+
22
+ integrate_targets(target_installation_results.pod_target_installation_results)
23
+ wire_target_dependencies(target_installation_results)
24
+ PodsProjectGeneratorResult.new(project, {}, target_installation_results)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1 @@
1
+ require 'cocoapods-headermap/gem_version'
@@ -0,0 +1,24 @@
1
+ # require 'cocoapods-headermap/command'
2
+
3
+ module CocoapodsHmapGod
4
+ Pod::HooksManager.register("cocoapods-headermap", :pre_install) do |context, options|
5
+
6
+ require 'cocoapods-headermap/build_settings'
7
+ require 'cocoapods-headermap/configuration'
8
+ require 'cocoapods-headermap/file_references_installer'
9
+ require 'cocoapods-headermap/headers_store'
10
+ require 'cocoapods-headermap/installer'
11
+ require 'cocoapods-headermap/multi_pods_project_generator'
12
+ require 'cocoapods-headermap/pod_target'
13
+ require 'cocoapods-headermap/sandbox'
14
+ require 'cocoapods-headermap/single_pods_project_generator'
15
+
16
+ Pod::Configuration.keep_symlink_headers = options[:keep_symlink_headers] if options.key?(:keep_symlink_headers)
17
+ Pod::Configuration.always_keep_symlink_headers = options[:always_keep_symlink_headers] if options.key?(:always_keep_symlink_headers)
18
+ end
19
+
20
+ Pod::HooksManager.register("cocoapods-hmap-god", :post_install) do |context|
21
+ # Hook `run_podfile_post_install_hooks` to change build settings rather than `:post_install`.
22
+ # The time to perform `:post_install` is right after the pod project is generated.
23
+ end
24
+ end
@@ -0,0 +1,12 @@
1
+ require File.expand_path('../../spec_helper', __FILE__)
2
+
3
+ module Pod
4
+ describe Command::Headermap do
5
+ describe 'CLAide' do
6
+ it 'registers it self' do
7
+ Command.parse(%w{ headermap }).should.be.instance_of Command::Headermap
8
+ end
9
+ end
10
+ end
11
+ end
12
+
@@ -0,0 +1,50 @@
1
+ require 'pathname'
2
+ ROOT = Pathname.new(File.expand_path('../../', __FILE__))
3
+ $:.unshift((ROOT + 'lib').to_s)
4
+ $:.unshift((ROOT + 'spec').to_s)
5
+
6
+ require 'bundler/setup'
7
+ require 'bacon'
8
+ require 'mocha-on-bacon'
9
+ require 'pretty_bacon'
10
+ require 'pathname'
11
+ require 'cocoapods'
12
+
13
+ Mocha::Configuration.prevent(:stubbing_non_existent_method)
14
+
15
+ require 'cocoapods_plugin'
16
+
17
+ #-----------------------------------------------------------------------------#
18
+
19
+ module Pod
20
+
21
+ # Disable the wrapping so the output is deterministic in the tests.
22
+ #
23
+ UI.disable_wrap = true
24
+
25
+ # Redirects the messages to an internal store.
26
+ #
27
+ module UI
28
+ @output = ''
29
+ @warnings = ''
30
+
31
+ class << self
32
+ attr_accessor :output
33
+ attr_accessor :warnings
34
+
35
+ def puts(message = '')
36
+ @output << "#{message}\n"
37
+ end
38
+
39
+ def warn(message = '', actions = [])
40
+ @warnings << "#{message}\n"
41
+ end
42
+
43
+ def print(message)
44
+ @output << message
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ #-----------------------------------------------------------------------------#
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cocoapods-headermap
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.7
5
+ platform: ruby
6
+ authors:
7
+ - menttofly
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-11-16 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: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
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
+ description: Improve Xcode compilation speed based on Header Maps.
42
+ email:
43
+ - 1028365614@qq.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".gitignore"
49
+ - Gemfile
50
+ - LICENSE.txt
51
+ - README.md
52
+ - Rakefile
53
+ - cocoapods-headermap.gemspec
54
+ - lib/cocoapods-headermap.rb
55
+ - lib/cocoapods-headermap/build_settings.rb
56
+ - lib/cocoapods-headermap/command.rb
57
+ - lib/cocoapods-headermap/command/headermap.rb
58
+ - lib/cocoapods-headermap/configuration.rb
59
+ - lib/cocoapods-headermap/file_references_installer.rb
60
+ - lib/cocoapods-headermap/gem_version.rb
61
+ - lib/cocoapods-headermap/header_maps_generator.rb
62
+ - lib/cocoapods-headermap/headers_store.rb
63
+ - lib/cocoapods-headermap/installer.rb
64
+ - lib/cocoapods-headermap/multi_pods_project_generator.rb
65
+ - lib/cocoapods-headermap/pod_target.rb
66
+ - lib/cocoapods-headermap/sandbox.rb
67
+ - lib/cocoapods-headermap/single_pods_project_generator.rb
68
+ - lib/cocoapods_plugin.rb
69
+ - spec/command/headermap_spec.rb
70
+ - spec/spec_helper.rb
71
+ homepage: https://github.com/
72
+ licenses:
73
+ - MIT
74
+ metadata: {}
75
+ post_install_message:
76
+ rdoc_options: []
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ required_rubygems_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ requirements: []
90
+ rubygems_version: 3.0.3
91
+ signing_key:
92
+ specification_version: 4
93
+ summary: Generate header maps file instead of creating soft link during pod installation.
94
+ Therefore, file IO can be reduced during the build process and the search speed
95
+ of header files can be improved.
96
+ test_files:
97
+ - spec/command/headermap_spec.rb
98
+ - spec/spec_helper.rb