cocoapods-mapfile 0.2.5 → 0.2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +51 -16
- data/lib/hmap/command/hmap_gen.rb +6 -3
- data/lib/hmap/command/hmap_reader.rb +10 -8
- data/lib/hmap/command/hmap_writer.rb +20 -12
- data/lib/hmap/constants.rb +27 -13
- data/lib/hmap/gem_version.rb +5 -0
- data/lib/hmap/helper/utils.rb +13 -4
- data/lib/hmap/hmap/hmap_bucketstr.rb +8 -0
- data/lib/hmap/hmap/hmap_reader.rb +2 -2
- data/lib/hmap/hmap/hmap_saver.rb +14 -40
- data/lib/hmap/hmap/hmap_struct.rb +13 -48
- data/lib/hmap/hmap/hmap_writer.rb +7 -4
- data/lib/hmap/hmap/mapfile.rb +6 -15
- data/lib/hmap/xc/header_entry.rb +15 -12
- data/lib/hmap/xc/pbx_helper.rb +11 -5
- data/lib/hmap/xc/resolver.rb +2 -2
- data/lib/hmap/xc/target/build_setting.rb +2 -7
- data/lib/hmap/xc/target/target.rb +23 -20
- data/lib/hmap/xc/target/target_context.rb +5 -4
- data/lib/hmap/xc/target/target_helper.rb +37 -12
- data/lib/hmap/xc/target/target_vfs.rb +0 -1
- data/lib/hmap/xc/target/xcconfig.rb +295 -0
- data/lib/hmap/xc/target/xcconfig_helper.rb +11 -13
- data/lib/hmap/xc/workspace/project.rb +9 -6
- data/lib/hmap/xc/workspace/project_helper.rb +21 -14
- data/lib/hmap/xc/workspace/workspace.rb +29 -7
- data/lib/hmap.rb +1 -1
- metadata +19 -4
- data/lib/hmap/version.rb +0 -5
data/lib/hmap/xc/header_entry.rb
CHANGED
@@ -11,45 +11,48 @@ module HMap
|
|
11
11
|
def project_buckets
|
12
12
|
h_name = File.basename(path)
|
13
13
|
h_dir = File.dirname(path)
|
14
|
-
|
14
|
+
{ h_name => ["#{h_dir}/", h_name] }
|
15
15
|
end
|
16
16
|
|
17
17
|
def module_buckets(moudle_name)
|
18
18
|
h_name = File.basename(path)
|
19
19
|
module_p = "#{moudle_name}/"
|
20
|
-
|
20
|
+
{ h_name => [module_p, h_name] }
|
21
21
|
end
|
22
22
|
|
23
23
|
def full_module_buckets(moudle_name)
|
24
24
|
h_name = File.basename(path)
|
25
25
|
h_dir = File.dirname(path)
|
26
26
|
module_k = "#{moudle_name}/#{h_name}"
|
27
|
-
|
27
|
+
{ module_k => ["#{h_dir}/", h_name] }
|
28
28
|
end
|
29
29
|
|
30
30
|
def project_buckets_extra
|
31
31
|
h_name = File.basename(path)
|
32
32
|
h_dir = File.dirname(path)
|
33
|
-
buckets =
|
34
|
-
buckets
|
35
|
-
|
33
|
+
buckets = {}
|
34
|
+
buckets[h_name] = ["#{h_dir}/", h_name] unless extra_keys.include?(h_name)
|
35
|
+
extra_keys.each { |key| buckets[key] = ["#{h_dir}/", h_name] }
|
36
|
+
buckets
|
36
37
|
end
|
37
38
|
|
38
39
|
def module_buckets_extra(moudle_name)
|
39
40
|
h_name = File.basename(path)
|
40
41
|
module_p = "#{moudle_name}/"
|
41
|
-
buckets =
|
42
|
-
buckets
|
43
|
-
|
42
|
+
buckets = {}
|
43
|
+
buckets[h_name] = [module_p, h_name] unless extra_keys.include?(h_name)
|
44
|
+
extra_keys.each { |key| buckets[key] = [module_p, h_name] }
|
45
|
+
buckets
|
44
46
|
end
|
45
47
|
|
46
48
|
def full_module_buckets_extra(moudle_name)
|
47
49
|
h_name = File.basename(path)
|
48
50
|
h_dir = File.dirname(path)
|
49
51
|
module_k = "#{moudle_name}/#{h_name}"
|
50
|
-
buckets =
|
51
|
-
buckets
|
52
|
-
|
52
|
+
buckets = {}
|
53
|
+
buckets[module_k] = ["#{h_dir}/", h_name] unless extra_keys.include?(module_k)
|
54
|
+
extra_keys.each { |key| buckets[key] = ["#{h_dir}/", h_name] }
|
55
|
+
buckets
|
53
56
|
end
|
54
57
|
end
|
55
58
|
end
|
data/lib/hmap/xc/pbx_helper.rb
CHANGED
@@ -1,15 +1,19 @@
|
|
1
1
|
module HMap
|
2
2
|
module PBXHelper
|
3
|
+
PBX_GROUP = '<group>'.freeze
|
4
|
+
PBX_SOURCE_ROOT = 'SOURCE_ROOT'.freeze
|
5
|
+
private_constant :PBX_GROUP, :PBX_SOURCE_ROOT
|
3
6
|
def self.get_groups(xct)
|
4
7
|
groups = xct.referrers.select { |e| e.is_a?(Constants::PBXGroup) } || []
|
5
8
|
groups += groups.flat_map { |g| get_groups(g) }
|
6
|
-
groups.compact
|
9
|
+
groups.compact
|
7
10
|
end
|
8
11
|
|
9
12
|
def self.group_paths(xct)
|
10
|
-
|
13
|
+
gs = get_groups(xct).reverse
|
14
|
+
ps = gs.map do |g|
|
11
15
|
s_hash = g.instance_variable_get('@simple_attributes_hash')
|
12
|
-
s_hash['path'] unless s_hash.nil?
|
16
|
+
s_hash['path'] unless s_hash.nil? && s_hash['sourceTree'] == PBX_GROUP
|
13
17
|
end.compact
|
14
18
|
File.join(*ps)
|
15
19
|
end
|
@@ -46,8 +50,10 @@ module HMap
|
|
46
50
|
p_path = File.dirname(project.path)
|
47
51
|
project.root_object.project_references.map do |sp|
|
48
52
|
ff = sp[:project_ref]
|
49
|
-
|
50
|
-
|
53
|
+
f_hash = ff.instance_variable_get('@simple_attributes_hash')
|
54
|
+
g_path = PBXHelper.group_paths(ff) if f_hash['sourceTree'] == PBX_GROUP
|
55
|
+
path = f_hash['path'] || ''
|
56
|
+
full_path = File.join(p_path, g_path || '', path)
|
51
57
|
Xcodeproj::Project.open(full_path)
|
52
58
|
end << project
|
53
59
|
end
|
data/lib/hmap/xc/resolver.rb
CHANGED
@@ -39,7 +39,7 @@ module HMap
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def project_build_settings(project_path)
|
42
|
-
targets =
|
42
|
+
targets = xcodebuild_project(project_path) || []
|
43
43
|
targets.first['buildSettings']
|
44
44
|
end
|
45
45
|
|
@@ -121,7 +121,7 @@ module HMap
|
|
121
121
|
command += %w[-json -showBuildSettings]
|
122
122
|
results = Executable.execute_command('xcodebuild', command, false)
|
123
123
|
index = results.index(/"action"/m)
|
124
|
-
reg = results[index
|
124
|
+
reg = results[index..]
|
125
125
|
reg = "[\n{\n#{reg}"
|
126
126
|
JSON.parse(reg) unless results.nil?
|
127
127
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'hmap/xc/target/target_vfs'
|
3
4
|
|
4
5
|
module HMap
|
@@ -63,13 +64,7 @@ module HMap
|
|
63
64
|
end
|
64
65
|
|
65
66
|
def symlink_to(path, need_platform)
|
66
|
-
|
67
|
-
|
68
|
-
filepath = Pathname.new(hmap_filepath(need_platform))
|
69
|
-
filepath.dirname.mkpath unless filepath.exist?
|
70
|
-
return if File.identical?(filepath, path)
|
71
|
-
|
72
|
-
filepath.make_symlink(path)
|
67
|
+
Utils.file_symlink_to(path, Pathname.new(hmap_filepath(need_platform)))
|
73
68
|
end
|
74
69
|
|
75
70
|
def write(data, need_platform)
|
@@ -42,35 +42,38 @@ module HMap
|
|
42
42
|
def xcconfig_paths
|
43
43
|
return @xcconfig_paths if defined?(@xcconfig_paths)
|
44
44
|
|
45
|
-
@xcconfig_paths = target.
|
45
|
+
@xcconfig_paths = target.build_configurations.flat_map do |configuration|
|
46
46
|
if configuration.is_a?(Constants::XCBuildConfiguration)
|
47
47
|
bcr = configuration.base_configuration_reference
|
48
48
|
unless bcr.nil?
|
49
49
|
s_path = PBXHelper.group_paths(bcr)
|
50
50
|
x = bcr.instance_variable_get('@simple_attributes_hash')['path'] || ''
|
51
|
-
File.expand_path
|
51
|
+
path = File.expand_path(File.join(project.project_dir, s_path, x))
|
52
|
+
xc = XCConfig.new(path)
|
53
|
+
inc = xc.includes_paths
|
54
|
+
path if inc.empty? || project.workspace.xcconfig_paths.none? { |pa| inc.include?(pa) }
|
52
55
|
end
|
53
56
|
end
|
54
57
|
end.compact
|
55
|
-
|
56
|
-
#
|
57
|
-
#
|
58
|
-
#
|
59
|
-
#
|
60
|
-
#
|
61
|
-
#
|
62
|
-
#
|
63
|
-
#
|
64
|
-
#
|
65
|
-
#
|
66
|
-
# #
|
67
|
-
#
|
68
|
-
#
|
69
|
-
#
|
70
|
-
#
|
71
|
-
#
|
58
|
+
|
59
|
+
# @xcconfig_paths = target.build_configuration_list.build_configurations.flat_map do |configuration|
|
60
|
+
# if configuration.is_a?(Constants::XCBuildConfiguration)
|
61
|
+
# bcr = configuration.base_configuration_reference
|
62
|
+
# # if bcr.nil?
|
63
|
+
# # ab_path = Pathname(project.project_dir + "hmap-#{target_name}.#{configuration.name}.xcconfig")
|
64
|
+
# # File.new(ab_path, 'w') unless ab_path.exist?
|
65
|
+
# # xc_ref = target.project.new_file(ab_path)
|
66
|
+
# # configuration.base_configuration_reference = xc_ref
|
67
|
+
# # target.project.save
|
68
|
+
# # ab_path
|
69
|
+
# # else
|
70
|
+
# unless bcr.nil?
|
71
|
+
# s_path = PBXHelper.group_paths(bcr)
|
72
|
+
# x = bcr.instance_variable_get('@simple_attributes_hash')['path'] || ''
|
73
|
+
# File.expand_path File.join(project.project_dir, s_path, x)
|
74
|
+
# end
|
72
75
|
# end
|
73
|
-
# end
|
76
|
+
# end.compact
|
74
77
|
end
|
75
78
|
end
|
76
79
|
end
|
@@ -1,9 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module HMap
|
4
|
-
class Target
|
4
|
+
class Target
|
5
5
|
class TargetContext < Context
|
6
6
|
attr_reader :product_name
|
7
|
+
|
7
8
|
def initialize(build_root, temp_dir, hmap_root, temp_name, build_dir, product_name, full_product_name, defines_modules, build_as_framework_swift)
|
8
9
|
super(build_root, temp_dir, hmap_root, temp_name, build_dir)
|
9
10
|
@full_product_name = full_product_name
|
@@ -11,15 +12,15 @@ module HMap
|
|
11
12
|
@defines_modules = defines_modules
|
12
13
|
@build_as_framework_swift = build_as_framework_swift
|
13
14
|
end
|
14
|
-
|
15
|
+
|
15
16
|
def build_as_framework_swift?
|
16
17
|
@build_as_framework_swift
|
17
18
|
end
|
18
|
-
|
19
|
+
|
19
20
|
def defines_modules?
|
20
21
|
@defines_modules
|
21
22
|
end
|
22
|
-
|
23
|
+
|
23
24
|
def build_path(platform)
|
24
25
|
path = super(platform)
|
25
26
|
File.join(path, @full_product_name)
|
@@ -16,29 +16,50 @@ module HMap
|
|
16
16
|
define_method(:all_non_framework_target_headers) do
|
17
17
|
return if build_as_framework?
|
18
18
|
|
19
|
+
return @all_non_framework_target_headers if defined? @all_non_framework_target_headers
|
20
|
+
|
19
21
|
p_h = public_entrys + private_entrys
|
20
|
-
p_h.
|
22
|
+
@all_non_framework_target_headers = p_h.inject({}) do |sum, entry|
|
23
|
+
sum.merge!(entry.full_module_buckets(product_name)) { |_, v1, _| v1 }
|
24
|
+
end
|
21
25
|
end
|
22
26
|
|
23
27
|
# all_targets include header full module path
|
24
28
|
define_method(:all_target_headers) do
|
29
|
+
return @all_target_headers if defined? @all_target_headers
|
30
|
+
|
25
31
|
p_h = public_entrys + private_entrys
|
26
|
-
p_h.
|
27
|
-
|
32
|
+
@all_target_headers = p_h.inject({}) do |sum, entry|
|
33
|
+
sum.merge!(entry.module_buckets(product_name)) { |_, v1, _| v1 }
|
34
|
+
sum.merge!(entry.full_module_buckets(product_name)) { |_, v1, _| v1 }
|
28
35
|
end
|
29
36
|
end
|
30
37
|
|
31
38
|
define_method(:project_headers) do
|
32
|
-
|
39
|
+
return @project_headers if defined? @project_headers
|
40
|
+
|
41
|
+
p_h = public_entrys + private_entrys
|
42
|
+
hs = p_h.inject({}) do |sum, entry|
|
43
|
+
sum.merge!(entry.module_buckets(product_name)) { |_, v1, _| v1 }
|
44
|
+
end
|
45
|
+
@project_headers = project_entrys.inject(hs) do |sum, entry|
|
46
|
+
sum.merge!(entry.project_buckets_extra) { |_, v1, _| v1 }
|
47
|
+
end
|
33
48
|
end
|
34
49
|
|
35
50
|
define_method(:own_target_headers) do
|
51
|
+
return @own_target_headers if defined? @own_target_headers
|
52
|
+
|
36
53
|
headers = public_entrys + private_entrys
|
37
|
-
|
38
|
-
|
39
|
-
|
54
|
+
hs = headers.inject({}) do |sum, entry|
|
55
|
+
sum.merge!(entry.module_buckets(product_name)) { |_, v1, _| v1 }
|
56
|
+
end
|
57
|
+
@own_target_headers = project_entrys.inject(hs) do |sum, entry|
|
58
|
+
sum.merge!(entry.project_buckets) { |_, v1, _| v1 }
|
59
|
+
sum.merge!(entry.full_module_buckets(product_name)) { |_, v1, _| v1 }
|
40
60
|
end
|
41
61
|
end
|
62
|
+
|
42
63
|
def build_root
|
43
64
|
project.build_root
|
44
65
|
end
|
@@ -52,7 +73,10 @@ module HMap
|
|
52
73
|
end
|
53
74
|
|
54
75
|
def product_name
|
55
|
-
target.
|
76
|
+
product_name = target.build_settings(target.build_configurations.first.name)['PRODUCT_NAME']
|
77
|
+
return target_name.gsub(/-/, '_') if product_name.nil? || product_name.include?('TARGET_NAME')
|
78
|
+
|
79
|
+
product_name
|
56
80
|
end
|
57
81
|
|
58
82
|
def full_product_name
|
@@ -70,13 +94,14 @@ module HMap
|
|
70
94
|
def build_dir
|
71
95
|
return @build_dir if defined?(@build_dir)
|
72
96
|
|
73
|
-
b_d = xcconfig_paths.
|
74
|
-
xc = Xcodeproj::Config.new(path)
|
75
|
-
!xc.attributes[Constants::CONFIGURATION_BUILD_DIR].nil?
|
76
|
-
end
|
97
|
+
b_d = xcconfig_paths.none? { |path| XCConfig.new(path).attributes[Constants::CONFIGURATION_BUILD_DIR].nil? }
|
77
98
|
@build_dir = target_name if b_d
|
78
99
|
end
|
79
100
|
|
101
|
+
def app_target?
|
102
|
+
Xcodeproj::Constants::PRODUCT_UTI_EXTENSIONS[target.symbol_type] == 'app'
|
103
|
+
end
|
104
|
+
|
80
105
|
def build_as_framework?
|
81
106
|
PBXHelper.build_as_framework?(target)
|
82
107
|
end
|
@@ -0,0 +1,295 @@
|
|
1
|
+
module HMap
|
2
|
+
# This class holds the data for a Xcode build settings file (xcconfig) and
|
3
|
+
# provides support for serialization.
|
4
|
+
#
|
5
|
+
class XCConfig
|
6
|
+
require 'set'
|
7
|
+
|
8
|
+
KEY_VALUE_PATTERN = /
|
9
|
+
(
|
10
|
+
[^=\[]+ # Any char, but not an assignment operator
|
11
|
+
# or subscript (non-greedy)
|
12
|
+
(?: # One or multiple conditional subscripts
|
13
|
+
\[
|
14
|
+
[^\]]* # The subscript key
|
15
|
+
(?:
|
16
|
+
= # The subscript comparison operator
|
17
|
+
[^\]]* # The subscript value
|
18
|
+
)?
|
19
|
+
\]
|
20
|
+
)*
|
21
|
+
)
|
22
|
+
\s* # Whitespaces after the key (needed because subscripts
|
23
|
+
# always end with ']')
|
24
|
+
= # The assignment operator
|
25
|
+
(.*) # The value
|
26
|
+
/x
|
27
|
+
private_constant :KEY_VALUE_PATTERN
|
28
|
+
|
29
|
+
INHERITED = %w($(inherited) ${inherited}).freeze
|
30
|
+
private_constant :INHERITED
|
31
|
+
|
32
|
+
INHERITED_REGEXP = Regexp.union(INHERITED)
|
33
|
+
private_constant :INHERITED_REGEXP
|
34
|
+
|
35
|
+
# @return [Hash{String => String}] The attributes of the settings file
|
36
|
+
# excluding frameworks, weak_framework and libraries.
|
37
|
+
#
|
38
|
+
attr_accessor :attributes
|
39
|
+
|
40
|
+
# @return [Array] The list of the configuration files included by this
|
41
|
+
# configuration file (`#include "SomeConfig"`).
|
42
|
+
#
|
43
|
+
attr_accessor :includes_paths
|
44
|
+
|
45
|
+
# @return [Hash{Symbol => Set<String>}] The other linker flags by key.
|
46
|
+
# Xcodeproj handles them in a dedicated way to prevent duplication
|
47
|
+
# of the libraries and of the frameworks.
|
48
|
+
#
|
49
|
+
def initialize(xcconfig_hash_or_file = {})
|
50
|
+
@attributes = {}
|
51
|
+
@includes = []
|
52
|
+
@include_attributes = {}
|
53
|
+
merge!(extract_hash(xcconfig_hash_or_file))
|
54
|
+
@includes_paths = @includes.map { |i| File.expand_path(i, @filepath.dirname) }
|
55
|
+
end
|
56
|
+
|
57
|
+
def inspect
|
58
|
+
to_hash.inspect
|
59
|
+
end
|
60
|
+
|
61
|
+
def ==(other)
|
62
|
+
other.attributes == attributes && other.includes_paths = @includes_paths
|
63
|
+
end
|
64
|
+
|
65
|
+
# @!group Serialization
|
66
|
+
#-------------------------------------------------------------------------#
|
67
|
+
|
68
|
+
# Sorts the internal data by setting name and serializes it in the xcconfig
|
69
|
+
# format.
|
70
|
+
#
|
71
|
+
# @example
|
72
|
+
#
|
73
|
+
# config = Config.new('PODS_ROOT' => '"$(SRCROOT)/Pods"', 'OTHER_LDFLAGS' => '-lxml2')
|
74
|
+
# config.to_s # => "OTHER_LDFLAGS = -lxml2\nPODS_ROOT = \"$(SRCROOT)/Pods\""
|
75
|
+
#
|
76
|
+
# @return [String] The serialized internal data.
|
77
|
+
#
|
78
|
+
def to_s(prefix = nil)
|
79
|
+
include_lines = @includes.map { |path| "#include \"#{normalized_xcconfig_path(path)}\"" }
|
80
|
+
settings = to_hash(prefix).sort_by(&:first).map { |k, v| "#{k} = #{v}".strip }
|
81
|
+
(include_lines + settings).join("\n") << "\n"
|
82
|
+
end
|
83
|
+
|
84
|
+
# Writes the serialized representation of the internal data to the given
|
85
|
+
# path.
|
86
|
+
#
|
87
|
+
# @param [Pathname] pathname
|
88
|
+
# The file where the data should be written to.
|
89
|
+
#
|
90
|
+
# @return [void]
|
91
|
+
#
|
92
|
+
def save_as(pathname, prefix = nil)
|
93
|
+
return if File.exist?(pathname) && (XCConfig.new(pathname) == self)
|
94
|
+
|
95
|
+
pathname.open('w') { |file| file << to_s(prefix) }
|
96
|
+
end
|
97
|
+
|
98
|
+
# The hash representation of the xcconfig. The hash includes the
|
99
|
+
# frameworks, the weak frameworks, the libraries and the simple other
|
100
|
+
# linker flags in the `Other Linker Flags` (`OTHER_LDFLAGS`).
|
101
|
+
#
|
102
|
+
# @note All the values are sorted to have a consistent output in Ruby
|
103
|
+
# 1.8.7.
|
104
|
+
#
|
105
|
+
# @return [Hash] The hash representation
|
106
|
+
#
|
107
|
+
def to_hash(prefix = nil)
|
108
|
+
result = attributes.dup
|
109
|
+
result.reject! { |_, v| INHERITED.any? { |i| i == v.to_s.strip } }
|
110
|
+
if prefix
|
111
|
+
Hash[result.map { |k, v| [prefix + k, v] }]
|
112
|
+
else
|
113
|
+
result
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
alias to_h to_hash
|
118
|
+
|
119
|
+
# @!group Merging
|
120
|
+
#-------------------------------------------------------------------------#
|
121
|
+
|
122
|
+
# Merges the given xcconfig representation in the receiver.
|
123
|
+
# @note If a key in the given hash already exists in the internal data
|
124
|
+
# then its value is appended.
|
125
|
+
#
|
126
|
+
# @param [Hash, Config] config
|
127
|
+
# The xcconfig representation to merge.
|
128
|
+
#
|
129
|
+
# @todo The logic to normalize an hash should be extracted and the
|
130
|
+
# initializer should not call this method.
|
131
|
+
#
|
132
|
+
# @return [void]
|
133
|
+
#
|
134
|
+
def merge!(xcconfig)
|
135
|
+
if xcconfig.is_a? XCConfig
|
136
|
+
merge_attributes!(xcconfig.attributes)
|
137
|
+
else
|
138
|
+
merge_attributes!(xcconfig.to_hash)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
alias << merge!
|
142
|
+
|
143
|
+
# Creates a new #{Config} with the data of the receiver merged with the
|
144
|
+
# given xcconfig representation.
|
145
|
+
#
|
146
|
+
# @param [Hash, Config] config
|
147
|
+
# The xcconfig representation to merge.
|
148
|
+
#
|
149
|
+
# @return [Config] the new xcconfig.
|
150
|
+
#
|
151
|
+
def merge(config)
|
152
|
+
dup.tap { |x| x.merge!(config) }
|
153
|
+
end
|
154
|
+
|
155
|
+
# @return [Config] A copy of the receiver.
|
156
|
+
#
|
157
|
+
def dup
|
158
|
+
HMap::XCConfig.new(to_hash.dup)
|
159
|
+
end
|
160
|
+
|
161
|
+
#-------------------------------------------------------------------------#
|
162
|
+
|
163
|
+
private
|
164
|
+
|
165
|
+
# @!group Private Helpers
|
166
|
+
|
167
|
+
# Returns a hash from the given argument reading it from disk if necessary.
|
168
|
+
#
|
169
|
+
# @param [String, Pathname, Hash] argument
|
170
|
+
# The source from where the hash should be extracted.
|
171
|
+
#
|
172
|
+
# @return [Hash]
|
173
|
+
#
|
174
|
+
def extract_hash(argument)
|
175
|
+
return argument if argument.is_a?(Hash)
|
176
|
+
|
177
|
+
if argument.respond_to? :read
|
178
|
+
@filepath = Pathname.new(argument.to_path)
|
179
|
+
hash_from_file_content(argument.read)
|
180
|
+
elsif File.readable?(argument.to_s)
|
181
|
+
@filepath = Pathname.new(argument.to_s)
|
182
|
+
hash_from_file_content(File.read(argument))
|
183
|
+
else
|
184
|
+
argument
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
# Returns a hash from the string representation of an Xcconfig file.
|
189
|
+
#
|
190
|
+
# @param [String] string
|
191
|
+
# The string representation of an xcconfig file.
|
192
|
+
#
|
193
|
+
# @return [Hash] the hash containing the xcconfig data.
|
194
|
+
#
|
195
|
+
def hash_from_file_content(string)
|
196
|
+
hash = {}
|
197
|
+
string.split("\n").each do |line|
|
198
|
+
uncommented_line = strip_comment(line)
|
199
|
+
e = extract_include(uncommented_line)
|
200
|
+
if e.nil?
|
201
|
+
key, value = extract_key_value(uncommented_line)
|
202
|
+
next unless key
|
203
|
+
value.gsub!(INHERITED_REGEXP) { |m| hash.fetch(key, m) }
|
204
|
+
hash[key] = value
|
205
|
+
else
|
206
|
+
@includes.push normalized_xcconfig_path(e)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
hash
|
210
|
+
end
|
211
|
+
|
212
|
+
# Merges the given attributes hash while ensuring values are not duplicated.
|
213
|
+
#
|
214
|
+
# @param [Hash] attributes
|
215
|
+
# The attributes hash to merge into @attributes.
|
216
|
+
#
|
217
|
+
# @return [void]
|
218
|
+
#
|
219
|
+
def merge_attributes!(attributes)
|
220
|
+
@attributes.merge!(attributes) do |_, v1, v2|
|
221
|
+
v1 = v1.strip
|
222
|
+
v2 = v2.strip
|
223
|
+
v1_split = v1.shellsplit
|
224
|
+
v2_split = v2.shellsplit
|
225
|
+
if (v2_split - v1_split).empty? || v1_split.first(v2_split.size) == v2_split
|
226
|
+
v1
|
227
|
+
elsif v2_split.first(v1_split.size) == v1_split
|
228
|
+
v2
|
229
|
+
else
|
230
|
+
"#{v1} #{v2}"
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
# Strips the comments from a line of an xcconfig string.
|
236
|
+
#
|
237
|
+
# @param [String] line
|
238
|
+
# the line to process.
|
239
|
+
#
|
240
|
+
# @return [String] the uncommented line.
|
241
|
+
#
|
242
|
+
def strip_comment(line)
|
243
|
+
line.partition('//').first
|
244
|
+
end
|
245
|
+
|
246
|
+
# Returns the file included by a line of an xcconfig string if present.
|
247
|
+
#
|
248
|
+
# @param [String] line
|
249
|
+
# the line to process.
|
250
|
+
#
|
251
|
+
# @return [String] the included file.
|
252
|
+
# @return [Nil] if no include was found in the line.
|
253
|
+
#
|
254
|
+
def extract_include(line)
|
255
|
+
regexp = /#include\s*"(.+)"/
|
256
|
+
match = line.match(regexp)
|
257
|
+
match[1] if match
|
258
|
+
end
|
259
|
+
|
260
|
+
# Returns the key and the value described by the given line of an xcconfig.
|
261
|
+
#
|
262
|
+
# @param [String] line
|
263
|
+
# the line to process.
|
264
|
+
#
|
265
|
+
# @return [Array] A tuple where the first entry is the key and the second
|
266
|
+
# entry is the value.
|
267
|
+
#
|
268
|
+
def extract_key_value(line)
|
269
|
+
match = line.match(KEY_VALUE_PATTERN)
|
270
|
+
if match
|
271
|
+
key = match[1]
|
272
|
+
value = match[2]
|
273
|
+
[key.strip, value.strip]
|
274
|
+
else
|
275
|
+
[]
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
# Normalizes the given path to an xcconfing file to be used in includes,
|
280
|
+
# appending the extension if necessary.
|
281
|
+
#
|
282
|
+
# @param [String] path
|
283
|
+
# The path of the file which will be included in the xcconfig.
|
284
|
+
#
|
285
|
+
# @return [String] The normalized path.
|
286
|
+
#
|
287
|
+
def normalized_xcconfig_path(path)
|
288
|
+
if File.extname(path) == '.xcconfig'
|
289
|
+
path
|
290
|
+
else
|
291
|
+
"#{path}.xcconfig"
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|