cocoapods-mapfile 0.2.5 → 0.2.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|