xcode-archive-cache 0.0.10.pre.1 → 0.0.12

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ea58d5804a6b809038af9c443a49426935c3f1b82673ce4029cadcd5dcdb21a2
4
- data.tar.gz: edae37d1c99f73465be2486e910e32bb4b445811d4ef8dd4db91e45853f34a6e
3
+ metadata.gz: b2121ee4ca94b2acfa38e1071a6f30209381464a7da5239e919d4b70cafd1d84
4
+ data.tar.gz: 9874700c995c65ee3ecaa4772a1aa6deba6868591b96da6d271b9ee1f32588df
5
5
  SHA512:
6
- metadata.gz: a753ce67b8129209b5da8e0afbdbd542da9660651ae47559fcfacbcf25ed9d35bedc45dbc05d23f13b33b1e4d05885f54bb43aaea2d3e2b4085f3fc1e960be63
7
- data.tar.gz: c90dee530d492db4c3986c0e0ca6d651e0099a8f0348cdb4f5fa0110a32d143932809bdfce295ab4dc36e8180456320a208ff9f927cc2478f9b8d086cc016c32
6
+ metadata.gz: 528092da4900b8232d71a9583ec0752c92ff2ee851bc13db3609c91c1a9aec3db4278abb777a3c574728d35b409b59ede6fc1481c0dafed49b93a396b994b114
7
+ data.tar.gz: c16c9ff1c2623437b5e29c0fea3cd1bc10cfe631c4df1772197595392b5a05286a8223294c20f9dc306b5ed47089f7c7c85c7eeb4138a940d2a37861c6266bdc
@@ -2,6 +2,8 @@ module XcodeArchiveCache
2
2
  module Build
3
3
  class ProductExtractor
4
4
 
5
+ include XcodeArchiveCache::Logs
6
+
5
7
  # @param [String] configuration
6
8
  # @param [String] derived_data_path
7
9
  #
@@ -17,7 +19,9 @@ module XcodeArchiveCache
17
19
  #
18
20
  def list_product_contents(built_node)
19
21
  file_paths = list_products(built_node)
20
- file_paths.select { |path| File.exist?(path) }.map { |path| File.realpath(path) }
22
+ file_paths
23
+ .select { |path| File.exist?(path) }
24
+ .map { |path| File.realpath(path) }
21
25
  end
22
26
 
23
27
  private
@@ -44,7 +48,7 @@ module XcodeArchiveCache
44
48
  elsif built_node.has_acceptable_product?
45
49
  list_single_product(built_node)
46
50
  else
47
- raise Informative, "#{built_node.name} has unsupported product type: #{built_node.native_target.product_type}"
51
+ raise XcodeArchiveCache::Informative, "#{built_node.name} has unsupported product type: #{built_node.native_target.product_type}"
48
52
  end
49
53
  end
50
54
 
@@ -56,7 +60,7 @@ module XcodeArchiveCache
56
60
  framework_glob = get_main_product_glob(built_node)
57
61
  framework_path = Dir.glob(framework_glob).first
58
62
  unless framework_path
59
- raise Informative, "Framework product not found for #{built_node.name}"
63
+ raise XcodeArchiveCache::Informative, "Framework product not found for #{built_node.name}"
60
64
  end
61
65
 
62
66
  framework_dsym_glob = File.join(File.dirname(framework_glob), built_node.dsym_file_name)
@@ -75,7 +79,7 @@ module XcodeArchiveCache
75
79
  product_glob = get_main_product_glob(built_node)
76
80
  product_path = Dir.glob(product_glob).first
77
81
  unless product_path
78
- raise Informative, "Product of type #{built_node.native_target.product_type} not found for #{built_node.name}"
82
+ raise XcodeArchiveCache::Informative, "Product of type #{built_node.native_target.product_type} not found for #{built_node.name}"
79
83
  end
80
84
 
81
85
  paths = [product_path]
@@ -83,8 +87,32 @@ module XcodeArchiveCache
83
87
  # this one is generated during Swift compilation
84
88
  # so we need to cache it as well
85
89
  #
86
- swift_objc_interface_header_path = built_node.swift_objc_interface_header_path
87
- paths << swift_objc_interface_header_path if swift_objc_interface_header_path
90
+ swift_objc_interface_header_glob = get_swift_objc_interface_header_glob(built_node)
91
+ swift_objc_interface_header_path = Dir.glob(swift_objc_interface_header_glob).first
92
+ if swift_objc_interface_header_path
93
+ debug("using Swift-ObjC interface header #{swift_objc_interface_header_path}")
94
+ paths << swift_objc_interface_header_path
95
+ end
96
+
97
+ swiftmodule_glob = get_swiftmodule_glob(built_node)
98
+ if swiftmodule_glob
99
+ swiftmodule_path = Dir.glob(swiftmodule_glob).first
100
+
101
+ if swiftmodule_path
102
+ debug("using swiftmodule #{swiftmodule_path}")
103
+ paths << swiftmodule_path
104
+ end
105
+ end
106
+
107
+ modulemap_glob = get_modulemap_glob(built_node)
108
+ if modulemap_glob
109
+ modulemap_path = Dir.glob(modulemap_glob).first
110
+
111
+ if modulemap_path
112
+ debug("using modulemap #{modulemap_path}")
113
+ paths << modulemap_path
114
+ end
115
+ end
88
116
 
89
117
  paths
90
118
  end
@@ -94,12 +122,57 @@ module XcodeArchiveCache
94
122
  # @return [String]
95
123
  #
96
124
  def get_main_product_glob(built_node)
97
- product_name = built_node.native_target.product_reference.name ?
98
- built_node.native_target.product_reference.name :
99
- built_node.native_target.product_reference.path
125
+ product_names = [File.basename(built_node.native_target.product_reference.path)]
126
+ if built_node.native_target.product_reference.name
127
+ product_names.push(File.basename(built_node.native_target.product_reference.name))
128
+ end
129
+
130
+ get_product_glob(product_names.select { |name| File.extname(name).length > 0 })
131
+ end
132
+
133
+ # @param [XcodeArchiveCache::BuildGraph::Node] built_node
134
+ #
135
+ # @return [String]
136
+ #
137
+ def get_swift_objc_interface_header_glob(built_node)
138
+ get_product_glob([File.basename(built_node.swift_objc_interface_header_file)])
139
+ end
140
+
141
+ # @param [XcodeArchiveCache::BuildGraph::Node] built_node
142
+ #
143
+ # @return [String]
144
+ #
145
+ def get_swiftmodule_glob(built_node)
146
+ if built_node.module_name
147
+ get_product_glob([built_node.module_name + ".swiftmodule"])
148
+ end
149
+ end
150
+
151
+ # @param [XcodeArchiveCache::BuildGraph::Node] built_node
152
+ #
153
+ # @return [String]
154
+ #
155
+ def get_modulemap_glob(built_node)
156
+ resulting_modulemap_file_name = built_node.resulting_modulemap_file_name
157
+ if resulting_modulemap_file_name
158
+ get_product_glob([resulting_modulemap_file_name])
159
+ else
160
+ modulemap_file_path = built_node.original_modulemap_file_path
161
+ if modulemap_file_path && File.exist?(modulemap_file_path)
162
+ modulemap_file_name = File.basename(modulemap_file_path)
163
+ get_product_glob([modulemap_file_name])
164
+ end
165
+ end
166
+ end
167
+
168
+ # @param [Array<String>] file_names
169
+ #
170
+ # @return [String]
171
+ #
172
+ def get_product_glob(file_names)
100
173
  File.join(derived_data_path,
101
174
  "**",
102
- File.basename(product_name))
175
+ "{#{file_names.join(",")}}")
103
176
  end
104
177
 
105
178
  # @param [String] framework_path
@@ -110,7 +183,7 @@ module XcodeArchiveCache
110
183
  executable_name = File.basename(framework_path, File.extname(framework_path))
111
184
  executable_path = File.join(framework_path, executable_name)
112
185
  unless File.exist?(executable_path)
113
- raise Informative, "Failed to find executable inside framework: #{framework_path}"
186
+ raise XcodeArchiveCache::Informative, "Failed to find executable inside framework: #{framework_path}"
114
187
  end
115
188
 
116
189
  uuids = list_bc_symbolmap_uuids(executable_path)
@@ -6,8 +6,8 @@ module XcodeArchiveCache
6
6
 
7
7
  # @param [XcodeArchiveCache::Xcodebuild::Executor] xcodebuild_executor
8
8
  #
9
- def initialize(native_target_finder, xcodebuild_executor)
10
- @build_settings_loader = XcodeArchiveCache::BuildSettings::Loader.new(xcodebuild_executor)
9
+ def initialize(native_target_finder, build_settings_loader)
10
+ @build_settings_loader = build_settings_loader
11
11
  @native_target_finder = native_target_finder
12
12
  @sha_calculator = NodeShaCalculator.new
13
13
  end
@@ -61,13 +61,17 @@ module XcodeArchiveCache
61
61
  display_name = target.display_name
62
62
  if target_stack.include?(display_name)
63
63
  target_stack.push(display_name)
64
- raise Informative, "Circular dependency detected: #{target_stack.join(" -> ")}"
64
+ raise XcodeArchiveCache::Informative, "Circular dependency detected: #{target_stack.join(" -> ")}"
65
65
  end
66
66
 
67
67
  node = ALL_NODES.select {|node| node.native_target.uuid == target.uuid && node.native_target.project == target.project}.first
68
68
  if node
69
69
  debug("already traversed this one")
70
- graph.add_multiple_nodes(node.subgraph) unless graph.nodes.include?(node)
70
+ unless graph.nodes.include?(node)
71
+ nodes_to_add = node.subgraph.select {|subgraph_node| !graph.nodes.include?(subgraph_node)}
72
+ graph.add_multiple_nodes(nodes_to_add)
73
+ end
74
+
71
75
  return node
72
76
  else
73
77
  debug("adding new node")
@@ -79,11 +83,7 @@ module XcodeArchiveCache
79
83
  dependencies = []
80
84
  target_stack.push(display_name)
81
85
 
82
- dependency_targets = target.dependencies.map {|dependency| native_target_finder.find_for_dependency(dependency)} +
83
- target.frameworks_build_phase.files.map {|file| native_target_finder.find_for_file(file)}
84
-
85
- # PBXNativeTarget has no custom equality check
86
- deduplicated_targets = dependency_targets.compact.uniq {|dependency_target| dependency_target.uuid + dependency_target.display_name}
86
+ deduplicated_targets = native_target_finder.find_native_dependencies(target)
87
87
  debug("dependency targets: #{deduplicated_targets.map(&:display_name)}")
88
88
 
89
89
  deduplicated_targets.each do |dependency_target|
@@ -141,7 +141,7 @@ module XcodeArchiveCache
141
141
  info("getting settings for #{target.display_name}")
142
142
  build_settings = build_settings_loader.get_settings(target.project.path, target.display_name)
143
143
  unless build_settings
144
- raise Informative, "No build settings loaded for #{target.display_name}"
144
+ raise XcodeArchiveCache::Informative, "No build settings loaded for #{target.display_name}"
145
145
  end
146
146
 
147
147
  build_settings
@@ -3,9 +3,14 @@ module XcodeArchiveCache
3
3
  class NativeTargetFinder
4
4
 
5
5
  # @param [Array<Xcodeproj::Project>] projects
6
+ # @param [String] build_configuration_name
6
7
  #
7
- def initialize(projects)
8
+ def initialize(projects, build_configuration_name)
8
9
  @all_targets = extract_targets(projects)
10
+ @build_configuration_name = build_configuration_name
11
+ @interpolator = XcodeArchiveCache::BuildSettings::StringInterpolator.new
12
+
13
+ setup_product_name_to_target_mapping
9
14
  end
10
15
 
11
16
  # @param [Array<Xcodeproj::Project>] projects
@@ -14,30 +19,67 @@ module XcodeArchiveCache
14
19
  #
15
20
  def extract_targets(projects)
16
21
  projects
17
- .map {|project| unnest(project)}
18
- .flatten
19
- .uniq
20
- .map(&:native_targets)
21
- .flatten
22
- .select {|target| !target.test_target_type?}
22
+ .map {|project| unnest(project)}
23
+ .flatten
24
+ .sort_by(&:path)
25
+ .inject([]) {|unique, current| unique.last && unique.last.path == current.path ? unique : unique + [current]}
26
+ .map(&:native_targets)
27
+ .flatten
28
+ .select {|target| !target.test_target_type?}
23
29
  end
24
30
 
25
31
  # @param [String] platform_name
26
32
  #
33
+ # @return [Array<Xcodeproj::Project::Object::PBXNativeTarget>]
34
+ #
27
35
  def set_platform_name_filter(platform_name)
28
36
  @platform_name = platform_name
29
37
  end
30
38
 
39
+ # @param [Xcodeproj::Project::Object::PBXNativeTarget] target
40
+ #
41
+ # @return [Array<Xcodeproj::Project::Object::PBXNativeTarget>]
42
+ #
43
+ def find_native_dependencies(target)
44
+ direct_dependencies = target
45
+ .dependencies
46
+ .map {|dependency| find_for_dependency(dependency)}
47
+ linked_dependencies = find_linked_dependencies(target)
48
+ join(direct_dependencies, linked_dependencies)
49
+ end
50
+
51
+ # @param [Xcodeproj::Project::Object::PBXAbstractTarget] target
52
+ #
53
+ # @return [Array<Xcodeproj::Project::Object::PBXAbstractTarget>]
54
+ #
55
+ def find_all_dependencies(target)
56
+ direct_dependencies = target
57
+ .dependencies
58
+ .map {|dependency| find_any_for_dependency(dependency)}
59
+ linked_dependencies = []
60
+
61
+ if target.is_a?(Xcodeproj::Project::Object::PBXNativeTarget)
62
+ linked_dependencies = find_linked_dependencies(target)
63
+ end
64
+
65
+ join(direct_dependencies, linked_dependencies)
66
+ end
67
+
31
68
  # @param [Xcodeproj::Project::Object::PBXTargetDependency] dependency
32
69
  #
33
70
  # @return [Xcodeproj::Project::Object::PBXNativeTarget]
34
71
  #
35
72
  def find_for_dependency(dependency)
36
73
  # targets from embedded projects are proxied
37
- target = dependency.target ? dependency.target : dependency.target_proxy.proxied_object
74
+ target = find_any_for_dependency(dependency)
38
75
  target.is_a?(Xcodeproj::Project::Object::PBXNativeTarget) ? target : nil
39
76
  end
40
77
 
78
+ def find_any_for_dependency(dependency)
79
+ target = dependency.target ? dependency.target : dependency.target_proxy.proxied_object
80
+ target && target.platform_name == platform_name ? target : nil
81
+ end
82
+
41
83
  # @param [Xcodeproj::Project::Object::PBXBuildFile] file
42
84
  #
43
85
  # @return [Xcodeproj::Project::Object::PBXNativeTarget]
@@ -60,7 +102,7 @@ module XcodeArchiveCache
60
102
  end
61
103
 
62
104
  if target == nil
63
- raise Informative, "Target for #{file.file_ref.path} not found"
105
+ raise XcodeArchiveCache::Informative, "Target for #{file.file_ref.path} not found"
64
106
  end
65
107
 
66
108
  target
@@ -68,7 +110,7 @@ module XcodeArchiveCache
68
110
  # products of sibling project targets are added as PBXFileReferences
69
111
  targets = find_with_product_path(file.file_ref.path)
70
112
  if targets.length > 1
71
- raise Informative, "Found more than one target with product #{File.basename(file.file_ref.path)} in:\n#{targets.map(&:project)}"
113
+ raise XcodeArchiveCache::Informative, "Found more than one target with product #{File.basename(file.file_ref.path)} in:\n#{targets.map(&:project)}"
72
114
  end
73
115
 
74
116
  targets.first
@@ -77,9 +119,16 @@ module XcodeArchiveCache
77
119
 
78
120
  # @param [String] product_name
79
121
  #
122
+ # @return [Xcodeproj::Project::Object::PBXNativeTarget]
123
+ #
80
124
  def find_for_product_name(product_name)
81
- all_targets.select {|native_target| native_target.name == product_name || native_target.product_reference.display_name == product_name}
82
- .first
125
+ canonical = all_targets
126
+ .select {|native_target| native_target.name == product_name || native_target.product_reference.display_name == product_name || native_target.product_reference.path == product_name }
127
+ .first
128
+
129
+ parsed = @product_name_to_target[product_name]
130
+
131
+ canonical ? canonical : parsed
83
132
  end
84
133
 
85
134
  private
@@ -92,6 +141,36 @@ module XcodeArchiveCache
92
141
  #
93
142
  attr_accessor :platform_name
94
143
 
144
+ # @return [String]
145
+ #
146
+ attr_reader :build_configuration_name
147
+
148
+ def setup_product_name_to_target_mapping
149
+ @product_name_to_target = Hash.new
150
+
151
+ @all_targets.each do |target|
152
+ build_settings = target.find_build_configuration(build_configuration_name, raise_if_not_found: false)&.build_settings
153
+ next unless build_settings
154
+
155
+ full_settings = build_settings
156
+ full_settings[XcodeArchiveCache::BuildSettings::TARGET_NAME_KEY] = target.name
157
+ product_name = @interpolator.interpolate(build_settings[XcodeArchiveCache::BuildSettings::PRODUCT_NAME_KEY], full_settings)
158
+
159
+ next if product_name == nil
160
+
161
+ product_name_extension = ""
162
+ case target.product_type
163
+ when Xcodeproj::Constants::PRODUCT_TYPE_UTI[:framework]
164
+ product_name_extension = ".framework"
165
+ when Xcodeproj::Constants::PRODUCT_TYPE_UTI[:static_library]
166
+ product_name_extension = ".a"
167
+ end
168
+
169
+ full_product_name = "#{product_name}#{product_name_extension}"
170
+ @product_name_to_target[full_product_name] = target
171
+ end
172
+ end
173
+
95
174
  # @param [Xcodeproj::Project] project
96
175
  #
97
176
  # @return [Array<Xcodeproj::Project>]
@@ -106,6 +185,28 @@ module XcodeArchiveCache
106
185
  [project] + nested_projects + subnested_projects
107
186
  end
108
187
 
188
+ # @param [Xcodeproj::Project::Object::PBXNativeTarget] target
189
+ #
190
+ # @return [Array<Xcodeproj::Project::Object::PBXNativeTarget>]
191
+ #
192
+ def find_linked_dependencies(target)
193
+ target
194
+ .frameworks_build_phase
195
+ .files
196
+ .map {|file| find_for_file(file)}
197
+ end
198
+
199
+ # @param [Array<Xcodeproj::Project::Object::PBXAbstractTarget>] direct_dependencies
200
+ # @params [Array<Xcodeproj::Project::Object::PBXNativeTarget>] linked_dependencies
201
+ #
202
+ # @return [Array<Xcodeproj::Project::Object::PBXAbstractTarget>]
203
+ #
204
+ def join(direct_dependencies, linked_dependencies)
205
+ (direct_dependencies + linked_dependencies)
206
+ .compact
207
+ .uniq(&:equatable_identifier)
208
+ end
209
+
109
210
  # @param [String] uuid
110
211
  #
111
212
  # @return [Xcodeproj::Project::Object::PBXNativeTarget]
@@ -128,7 +229,16 @@ module XcodeArchiveCache
128
229
  # @return [Array<Xcodeproj::Project::Object::PBXNativeTarget>]
129
230
  #
130
231
  def find_with_product_path(path)
131
- all_targets.select {|target| target.platform_name == platform_name && target.product_reference.path == path}
232
+ canonical = all_targets.select {|target| target.platform_name == platform_name && target.product_reference.path == path }
233
+ parsed = @product_name_to_target[File.basename(path)]
234
+
235
+ if canonical.length > 0
236
+ canonical
237
+ elsif parsed
238
+ [parsed]
239
+ else
240
+ []
241
+ end
132
242
  end
133
243
  end
134
244
  end
@@ -34,6 +34,10 @@ module XcodeArchiveCache
34
34
  #
35
35
  attr_accessor :build_settings
36
36
 
37
+ # @return [Array<Xcodeproj::Project::Object::PBXNativeTarget>]
38
+ #
39
+ attr_reader :targets_injected_to
40
+
37
41
  # @param [String] name
38
42
  # @param [Xcodeproj::Project::Object::PBXNativeTarget] native_target
39
43
  # @param [Boolean] is_root
@@ -44,6 +48,7 @@ module XcodeArchiveCache
44
48
  @is_root = is_root
45
49
  @dependent = []
46
50
  @dependencies = []
51
+ @targets_injected_to = []
47
52
  @state = :unknown
48
53
  end
49
54
 
@@ -91,8 +96,8 @@ module XcodeArchiveCache
91
96
 
92
97
  # @return [String]
93
98
  #
94
- def modulemap_file_path
95
- modulemap_file = build_settings[XcodeArchiveCache::BuildSettings::MODULEMAP_FILE_KEY]
99
+ def original_modulemap_file_path
100
+ modulemap_file = modulemap_file_name
96
101
  return unless modulemap_file
97
102
 
98
103
  Pathname.new(modulemap_file).absolute? ? modulemap_file : File.join(File.dirname(native_target.project.path), modulemap_file)
@@ -100,11 +105,12 @@ module XcodeArchiveCache
100
105
 
101
106
  # @return [String]
102
107
  #
103
- def swift_objc_interface_header_path
104
- header_file = swift_objc_interface_header_file
105
- return if header_file == nil
106
-
107
- File.join(build_settings[XcodeArchiveCache::BuildSettings::DERIVED_SOURCES_DIR_KEY], header_file)
108
+ def resulting_modulemap_file_name
109
+ if module_name
110
+ module_name + ".modulemap"
111
+ else
112
+ File.basename(modulemap_file_name)
113
+ end
108
114
  end
109
115
 
110
116
  # @return [String]
@@ -127,6 +133,12 @@ module XcodeArchiveCache
127
133
  build_settings[XcodeArchiveCache::BuildSettings::PRODUCT_MODULE_NAME_KEY]
128
134
  end
129
135
 
136
+ # @return [String]
137
+ #
138
+ def modulemap_file_name
139
+ build_settings[XcodeArchiveCache::BuildSettings::MODULEMAP_FILE_KEY]
140
+ end
141
+
130
142
  # @return [Array<Node>]
131
143
  # Direct + transitive dependents
132
144
  #
@@ -2,6 +2,10 @@ module XcodeArchiveCache
2
2
  module BuildGraph
3
3
  class NodeShaCalculator
4
4
 
5
+ def initialize
6
+ @own_sha = calculate_own_sources_sha
7
+ end
8
+
5
9
  # @param [XcodeArchiveCache::BuildGraph::Node] node
6
10
  #
7
11
  def calculate(node)
@@ -24,6 +28,20 @@ module XcodeArchiveCache
24
28
 
25
29
  private
26
30
 
31
+ # @return [String]
32
+ #
33
+ attr_reader :own_sha
34
+
35
+ # @return [String]
36
+ #
37
+ def calculate_own_sources_sha
38
+ root = Pathname.new(File.expand_path('../', File.dirname(__FILE__)))
39
+ source_file_glob = File.join(root.realpath.to_s, "**", "*.rb")
40
+ source_file_paths = Dir.glob(source_file_glob)
41
+
42
+ calculate_sha(source_file_paths)
43
+ end
44
+
27
45
  # @param [XcodeArchiveCache::BuildGraph::Node] node
28
46
  #
29
47
  # @return [Array<String>]
@@ -36,7 +54,7 @@ module XcodeArchiveCache
36
54
  inputs << list_build_phase_inputs(build_phase)
37
55
  end
38
56
 
39
- modulemap_file_path = node.modulemap_file_path
57
+ modulemap_file_path = node.original_modulemap_file_path
40
58
  inputs << modulemap_file_path if modulemap_file_path
41
59
 
42
60
  # file path order should not affect evaluation result
@@ -74,7 +92,7 @@ module XcodeArchiveCache
74
92
  # @param [Array<String>] dependency_shas
75
93
  #
76
94
  def save_auxiliary_data(build_settings, dependency_shas, tempfile)
77
- file_contents = build_settings + dependency_shas.join("\n")
95
+ file_contents = build_settings + dependency_shas.join("\n") + "\nXCODE-ARCHIVE-CACHE: #{own_sha}\n"
78
96
  tempfile << file_contents
79
97
  tempfile.flush
80
98
  end
@@ -73,6 +73,7 @@ module XcodeArchiveCache
73
73
  original_platform = settings[EFFECTIVE_PLATFORM_NAME_KEY]
74
74
  simulator_platform = settings[CORRESPONDING_SIMULATOR_PLATFORM_NAME_KEY]
75
75
  settings[EFFECTIVE_PLATFORM_NAME_KEY] = "-#{simulator_platform}"
76
+ settings[PLATFORM_NAME_KEY] = simulator_platform
76
77
 
77
78
  configuration = settings[CONFIGURATION_KEY]
78
79
  path_regexp = Regexp.new("#{configuration}#{original_platform}")
@@ -82,6 +83,7 @@ module XcodeArchiveCache
82
83
  end
83
84
  end
84
85
 
86
+ PLATFORM_NAME_KEY = "PLATFORM_NAME".freeze
85
87
  EFFECTIVE_PLATFORM_NAME_KEY = "EFFECTIVE_PLATFORM_NAME".freeze
86
88
  CORRESPONDING_SIMULATOR_PLATFORM_NAME_KEY = "CORRESPONDING_SIMULATOR_PLATFORM_NAME".freeze
87
89
  CONFIGURATION_KEY = "CONFIGURATION".freeze
@@ -1,6 +1,8 @@
1
1
  module XcodeArchiveCache
2
2
  module BuildSettings
3
3
 
4
+ PRODUCT_NAME_KEY = "PRODUCT_NAME".freeze
5
+ TARGET_NAME_KEY = "TARGET_NAME".freeze
4
6
  FULL_PRODUCT_NAME_KEY = "FULL_PRODUCT_NAME".freeze
5
7
  DWARF_DSYM_FILE_NAME_KEY = "DWARF_DSYM_FILE_NAME".freeze
6
8
  MODULEMAP_FILE_KEY = "MODULEMAP_FILE".freeze
@@ -1,11 +1,24 @@
1
1
  module XcodeArchiveCache
2
2
  module BuildSettings
3
+ class SettingEntry
4
+ attr_reader :name
5
+ attr_reader :modifiers
6
+ attr_reader :full_string
7
+
8
+ def initialize(name, modifiers, full_string)
9
+ @name = name
10
+ @modifiers = modifiers
11
+ @full_string = full_string
12
+ end
13
+ end
14
+
3
15
  class Parser
4
16
 
5
17
  def initialize
6
18
  @setting_name_regex = Regexp.new("^(?<#{SETTING_NAME_GROUP}>#{SETTING_NAME_CHARACTERS})\s=")
7
19
  @setting_value_regex = Regexp.new("^#{SETTING_NAME_CHARACTERS}\s=\s(?<#{SETTING_VALUE_GROUP}>.+)$")
8
20
  @setting_entry_regex = create_entry_regex
21
+ @setting_entry_part_regex = Regexp.new("#{SETTING_ENTRY_PART_CHARACTERS}")
9
22
  @setting_entry_name_regex = Regexp.new(SETTING_NAME_CHARACTERS)
10
23
  end
11
24
 
@@ -13,12 +26,18 @@ module XcodeArchiveCache
13
26
  #
14
27
  # @return [Array<String>]
15
28
  #
16
- def find_all_names(string)
29
+ def find_all_entries(string)
30
+ return nil if string == nil
31
+
17
32
  string.scan(setting_entry_regex)
18
- .map {|entry| entry.scan(setting_entry_name_regex).first}
19
- .flatten
33
+ .map {|entry|
34
+ parts = entry.scan(setting_entry_part_regex)
35
+ name = parts.first
36
+ modifiers = parts.drop(1)
37
+
38
+ name != nil ? SettingEntry.new(name, modifiers, entry) : nil
39
+ }
20
40
  .compact
21
- .uniq
22
41
  end
23
42
 
24
43
  # @param [String] string
@@ -47,7 +66,7 @@ module XcodeArchiveCache
47
66
  #
48
67
  # @return [Regexp]
49
68
  #
50
- def create_entry_regex(characters = SETTING_NAME_CHARACTERS)
69
+ def create_entry_regex(characters = SETTING_ALL_CHARACTERS)
51
70
  Regexp.new("\\$[({]#{characters}[)}]")
52
71
  end
53
72
 
@@ -65,10 +84,14 @@ module XcodeArchiveCache
65
84
  #
66
85
  attr_reader :setting_entry_regex
67
86
 
87
+ attr_reader :setting_entry_part_regex
88
+
68
89
  # @return [Regexp]
69
90
  #
70
91
  attr_reader :setting_entry_name_regex
71
92
 
93
+ SETTING_ALL_CHARACTERS = "[A-Za-z0-9_:]+".freeze
94
+ SETTING_ENTRY_PART_CHARACTERS = "[A-Za-z0-9_]+".freeze
72
95
  SETTING_NAME_CHARACTERS = "[A-Z0-9_]+".freeze
73
96
  SETTING_NAME_GROUP = "name".freeze
74
97
  SETTING_VALUE_GROUP = "value".freeze
@@ -12,15 +12,17 @@ module XcodeArchiveCache
12
12
  # @return [String]
13
13
  #
14
14
  def interpolate(string, build_settings)
15
- names = parser.find_all_names(string)
15
+ return nil if string == nil
16
+
17
+ entries = parser.find_all_entries(string)
16
18
  result = string
17
19
 
18
- names.each do |name|
19
- value = build_settings[name]
20
+ entries.each do |entry|
21
+ value = build_settings[entry.name]
20
22
  next unless value
21
23
 
22
- replacement_regex = parser.create_entry_regex(name)
23
- result = result.gsub(replacement_regex, value)
24
+ modified_value = modify_setting_value(value, entry.modifiers)
25
+ result = result.gsub(entry.full_string, modified_value)
24
26
  end
25
27
 
26
28
  result
@@ -31,6 +33,20 @@ module XcodeArchiveCache
31
33
  # @return [Parser]
32
34
  #
33
35
  attr_accessor :parser
36
+
37
+ def modify_setting_value(value, modifiers)
38
+ modified_value = value
39
+
40
+ modifiers.each do |modifier|
41
+ case modifier
42
+ when "c99extidentifier"
43
+ modified_value = modified_value.gsub(/[-\s]/, "_")
44
+ else
45
+ end
46
+ end
47
+
48
+ modified_value
49
+ end
34
50
  end
35
51
  end
36
52
  end