xcode-archive-cache 0.0.10 → 0.0.11

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: ff86c853bc7b50f265964695cd55edd14821c821f5d27a1f916dcc23ccc1c4b4
4
- data.tar.gz: a11e6dd9c98f59526f6f5329aab00acdcc58b5d7e2b65d83b6a1348d647a2323
3
+ metadata.gz: 3c3de4b956fe76ce673329ecf9977a911d3c6bb3055c00e59c3e6903cb16e6b2
4
+ data.tar.gz: 92253d7316a2a716b71a053f182483e7af54aeb1662111175f3e071909d79998
5
5
  SHA512:
6
- metadata.gz: a71f194f4af63d93ee4f256977eb98525065599a36f270215c5c0f3a18cb8742957bb8f2e407497a7629f05ba18b9532d093d02b1dec305fcf4f82f815473431
7
- data.tar.gz: ba25058d81d37e12594422d9a765d07fb8af192b53fe980ca3b4da3e1eac61f5a0bc69454f406be92094742e7809dbe8f4887d33e48b305c869733e5c581a4d8
6
+ metadata.gz: 88b0a7e44eecbdc426755761dd5df10fb0e1cff4a00c44f915df1f65515685ce3f2527d8d9b1173ea439bff032d49f4875f32a859291a702f829d378103c8234
7
+ data.tar.gz: c63650b58e921da5e38bb8648d0e6e3cfeddb55165e72f8984511c769a139b6ab3108350c0e684ed27ed9dbf9e02ef46135cc315a182ebc00586bb33c3fdae1f
@@ -48,7 +48,7 @@ module XcodeArchiveCache
48
48
  elsif built_node.has_acceptable_product?
49
49
  list_single_product(built_node)
50
50
  else
51
- 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}"
52
52
  end
53
53
  end
54
54
 
@@ -60,7 +60,7 @@ module XcodeArchiveCache
60
60
  framework_glob = get_main_product_glob(built_node)
61
61
  framework_path = Dir.glob(framework_glob).first
62
62
  unless framework_path
63
- raise Informative, "Framework product not found for #{built_node.name}"
63
+ raise XcodeArchiveCache::Informative, "Framework product not found for #{built_node.name}"
64
64
  end
65
65
 
66
66
  framework_dsym_glob = File.join(File.dirname(framework_glob), built_node.dsym_file_name)
@@ -79,7 +79,7 @@ module XcodeArchiveCache
79
79
  product_glob = get_main_product_glob(built_node)
80
80
  product_path = Dir.glob(product_glob).first
81
81
  unless product_path
82
- 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}"
83
83
  end
84
84
 
85
85
  paths = [product_path]
@@ -181,7 +181,7 @@ module XcodeArchiveCache
181
181
  executable_name = File.basename(framework_path, File.extname(framework_path))
182
182
  executable_path = File.join(framework_path, executable_name)
183
183
  unless File.exist?(executable_path)
184
- raise Informative, "Failed to find executable inside framework: #{framework_path}"
184
+ raise XcodeArchiveCache::Informative, "Failed to find executable inside framework: #{framework_path}"
185
185
  end
186
186
 
187
187
  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,7 +61,7 @@ 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
@@ -83,11 +83,7 @@ module XcodeArchiveCache
83
83
  dependencies = []
84
84
  target_stack.push(display_name)
85
85
 
86
- dependency_targets = target.dependencies.map {|dependency| native_target_finder.find_for_dependency(dependency)} +
87
- target.frameworks_build_phase.files.map {|file| native_target_finder.find_for_file(file)}
88
-
89
- # PBXNativeTarget has no custom equality check
90
- 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)
91
87
  debug("dependency targets: #{deduplicated_targets.map(&:display_name)}")
92
88
 
93
89
  deduplicated_targets.each do |dependency_target|
@@ -145,7 +141,7 @@ module XcodeArchiveCache
145
141
  info("getting settings for #{target.display_name}")
146
142
  build_settings = build_settings_loader.get_settings(target.project.path, target.display_name)
147
143
  unless build_settings
148
- raise Informative, "No build settings loaded for #{target.display_name}"
144
+ raise XcodeArchiveCache::Informative, "No build settings loaded for #{target.display_name}"
149
145
  end
150
146
 
151
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
@@ -25,20 +30,56 @@ module XcodeArchiveCache
25
30
 
26
31
  # @param [String] platform_name
27
32
  #
33
+ # @return [Array<Xcodeproj::Project::Object::PBXNativeTarget>]
34
+ #
28
35
  def set_platform_name_filter(platform_name)
29
36
  @platform_name = platform_name
30
37
  end
31
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
+
32
68
  # @param [Xcodeproj::Project::Object::PBXTargetDependency] dependency
33
69
  #
34
70
  # @return [Xcodeproj::Project::Object::PBXNativeTarget]
35
71
  #
36
72
  def find_for_dependency(dependency)
37
73
  # targets from embedded projects are proxied
38
- target = dependency.target ? dependency.target : dependency.target_proxy.proxied_object
74
+ target = find_any_for_dependency(dependency)
39
75
  target.is_a?(Xcodeproj::Project::Object::PBXNativeTarget) ? target : nil
40
76
  end
41
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
+
42
83
  # @param [Xcodeproj::Project::Object::PBXBuildFile] file
43
84
  #
44
85
  # @return [Xcodeproj::Project::Object::PBXNativeTarget]
@@ -61,7 +102,7 @@ module XcodeArchiveCache
61
102
  end
62
103
 
63
104
  if target == nil
64
- raise Informative, "Target for #{file.file_ref.path} not found"
105
+ raise XcodeArchiveCache::Informative, "Target for #{file.file_ref.path} not found"
65
106
  end
66
107
 
67
108
  target
@@ -69,7 +110,7 @@ module XcodeArchiveCache
69
110
  # products of sibling project targets are added as PBXFileReferences
70
111
  targets = find_with_product_path(file.file_ref.path)
71
112
  if targets.length > 1
72
- 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)}"
73
114
  end
74
115
 
75
116
  targets.first
@@ -78,9 +119,16 @@ module XcodeArchiveCache
78
119
 
79
120
  # @param [String] product_name
80
121
  #
122
+ # @return [Xcodeproj::Project::Object::PBXNativeTarget]
123
+ #
81
124
  def find_for_product_name(product_name)
82
- all_targets.select {|native_target| native_target.name == product_name || native_target.product_reference.display_name == product_name}
83
- .first
125
+ canonical = all_targets
126
+ .select {|native_target| native_target.name == product_name || native_target.product_reference.display_name == product_name}
127
+ .first
128
+
129
+ parsed = @product_name_to_target[product_name]
130
+
131
+ canonical ? canonical : parsed
84
132
  end
85
133
 
86
134
  private
@@ -93,6 +141,36 @@ module XcodeArchiveCache
93
141
  #
94
142
  attr_accessor :platform_name
95
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
+
96
174
  # @param [Xcodeproj::Project] project
97
175
  #
98
176
  # @return [Array<Xcodeproj::Project>]
@@ -107,6 +185,28 @@ module XcodeArchiveCache
107
185
  [project] + nested_projects + subnested_projects
108
186
  end
109
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
+
110
210
  # @param [String] uuid
111
211
  #
112
212
  # @return [Xcodeproj::Project::Object::PBXNativeTarget]
@@ -129,7 +229,16 @@ module XcodeArchiveCache
129
229
  # @return [Array<Xcodeproj::Project::Object::PBXNativeTarget>]
130
230
  #
131
231
  def find_with_product_path(path)
132
- 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
133
242
  end
134
243
  end
135
244
  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
data/lib/config/config.rb CHANGED
@@ -52,7 +52,7 @@ module XcodeArchiveCache
52
52
  def active_configuration
53
53
  configuration = configurations.select{|config| config.name == active_configuration_name }.first
54
54
  if configuration == nil
55
- raise Informative, "Found no configuration with name \"#{active_configuration_name}\""
55
+ raise XcodeArchiveCache::Informative, "Found no configuration with name \"#{active_configuration_name}\""
56
56
  end
57
57
 
58
58
  configuration
@@ -172,7 +172,7 @@ module XcodeArchiveCache
172
172
  begin
173
173
  eval(contents, nil, path)
174
174
  rescue Exception => e
175
- raise Informative, "Invalid #{File.basename(path)} file: #{e.message}"
175
+ raise XcodeArchiveCache::Informative, "Invalid #{File.basename(path)} file: #{e.message}"
176
176
  end
177
177
  end
178
178
 
@@ -0,0 +1,26 @@
1
+ module XCConfigExtensions
2
+ # @return [Bool]
3
+ #
4
+ def has_xcconfig?
5
+ base_configuration_reference != nil
6
+ end
7
+
8
+ # @return [String]
9
+ #
10
+ def get_xcconfig_path
11
+ base_configuration_reference.real_path
12
+ end
13
+ end
14
+
15
+ module ProjectDir
16
+ # @return [String]
17
+ #
18
+ def get_project_dir
19
+ File.dirname(project.path)
20
+ end
21
+ end
22
+
23
+ class Xcodeproj::Project::Object::XCBuildConfiguration
24
+ include XCConfigExtensions
25
+ include ProjectDir
26
+ end
@@ -0,0 +1,58 @@
1
+ module TargetEqualityCheck
2
+ # @return [String]
3
+ #
4
+ def equatable_identifier
5
+ uuid + display_name
6
+ end
7
+ end
8
+
9
+ module BuildConfigurationSearch
10
+ # @param [String] configuration_name
11
+ #
12
+ # @return [Xcodeproj::Project::Object::XCBuildConfiguration]
13
+ #
14
+ def find_build_configuration(configuration_name, raise_if_not_found: true)
15
+ build_configuration = build_configurations
16
+ .select { |configuration| configuration.name == configuration_name }
17
+ .first
18
+ if raise_if_not_found && build_configuration == nil
19
+ raise XcodeArchiveCache::Informative, "#{configuration_name} build configuration not found on target #{display_name} #{project.path}"
20
+ end
21
+
22
+ build_configuration
23
+ end
24
+ end
25
+
26
+ module SchellScriptBuildPhaseSearch
27
+ # @param [XcodeArchiveCache::BuildSettings::StringInterpolator] build_settings_interpolator
28
+ # @param [XcodeArchiveCache::BuildSettings::Container] build_settings
29
+ # @param [String] script_name
30
+ #
31
+ # @return [String]
32
+ #
33
+ def find_script(build_settings_interpolator, build_settings, script_name)
34
+ shell_script_build_phases.each do |phase|
35
+ if phase.display_name == script_name
36
+ return build_settings_interpolator.interpolate(phase.shell_script, build_settings)
37
+ .gsub(/^"|"$/, "")
38
+ .strip
39
+ end
40
+ end
41
+
42
+ nil
43
+ end
44
+ end
45
+
46
+ class Xcodeproj::Project::Object::PBXAggregateTarget
47
+ include XcodeArchiveCache::Logs
48
+ include TargetEqualityCheck
49
+ include BuildConfigurationSearch
50
+ include SchellScriptBuildPhaseSearch
51
+ end
52
+
53
+ class Xcodeproj::Project::Object::PBXNativeTarget
54
+ include XcodeArchiveCache::Logs
55
+ include TargetEqualityCheck
56
+ include BuildConfigurationSearch
57
+ include SchellScriptBuildPhaseSearch
58
+ end
@@ -248,11 +248,14 @@ module XcodeArchiveCache
248
248
  replaced = replace_flag_value(build_configuration.build_settings, setting, flag_name, possible_old_values, new_value) || replaced
249
249
  end
250
250
 
251
- if build_configuration.base_configuration_reference
252
- xcconfig_path = build_configuration.base_configuration_reference.real_path
253
- project_dir = File.dirname(build_configuration.project.path)
254
-
255
- replaced = replace_flag_value_in_xcconfig_recursively(xcconfig_path, project_dir, setting_keys, flag_name, possible_old_values, new_value) || replaced
251
+ if build_configuration.has_xcconfig?
252
+ replaced = replace_flag_value_in_xcconfig_recursively(
253
+ build_configuration.get_xcconfig_path,
254
+ build_configuration.get_project_dir,
255
+ setting_keys,
256
+ flag_name,
257
+ possible_old_values,
258
+ new_value) || replaced
256
259
  end
257
260
 
258
261
  if !replaced && add_if_missing
@@ -306,7 +309,7 @@ module XcodeArchiveCache
306
309
  is_string = build_settings.is_a?(String)
307
310
  build_settings = build_settings.split(" ") if is_string
308
311
  full_value = get_full_flag_value(flag_name, new_value)
309
- old_value_regexps = possible_old_values.map { |value| Regexp.new("#{value}\"*$") }
312
+ old_value_regexps = possible_old_values.map { |value| Regexp.new("/#{value}\"*$") }
310
313
 
311
314
  updated_settings = build_settings
312
315
  .map { |line| line.split(" ") }
@@ -136,7 +136,7 @@ module XcodeArchiveCache
136
136
 
137
137
  debug("adding #{paths} to #{target.display_name}")
138
138
 
139
- build_configuration = find_build_configuration(target)
139
+ build_configuration = target.find_build_configuration(configuration_name)
140
140
  paths.each do |path|
141
141
  build_flags_changer.add_headers_search_path(build_configuration, path)
142
142
  build_flags_changer.add_iquote_path(build_configuration, path)
@@ -175,7 +175,7 @@ module XcodeArchiveCache
175
175
  debug("adding #{prebuilt_node.name} as prebuilt to #{dependent_target.display_name}")
176
176
 
177
177
  unless prebuilt_node.has_acceptable_product?
178
- raise Informative, "#{prebuilt_node.name} has unsupported product type: #{prebuilt_node.native_target.product_type}"
178
+ raise XcodeArchiveCache::Informative, "#{prebuilt_node.name} has unsupported product type: #{prebuilt_node.native_target.product_type}"
179
179
  end
180
180
 
181
181
  if prebuilt_node.has_framework_product?
@@ -193,7 +193,7 @@ module XcodeArchiveCache
193
193
  # @param [Xcodeproj::Project::Object::PBXNativeTarget] dependent_target
194
194
  #
195
195
  def add_as_prebuilt_framework(prebuilt_node, dependent_target)
196
- build_configuration = find_build_configuration(dependent_target)
196
+ build_configuration = dependent_target.find_build_configuration(configuration_name)
197
197
 
198
198
  artifact_location = storage.get_storage_path(prebuilt_node)
199
199
  build_flags_changer.replace_or_add_framework_search_path(build_configuration, prebuilt_node.native_target.name, artifact_location)
@@ -210,7 +210,7 @@ module XcodeArchiveCache
210
210
  # @param [Xcodeproj::Project::Object::PBXNativeTarget] dependent_target
211
211
  #
212
212
  def add_as_prebuilt_static_lib(prebuilt_node, dependent_target)
213
- build_configuration = find_build_configuration(dependent_target)
213
+ build_configuration = dependent_target.find_build_configuration(configuration_name)
214
214
 
215
215
  injected_modulemap_file_path = storage.get_modulemap_path(prebuilt_node)
216
216
  if injected_modulemap_file_path
@@ -236,17 +236,6 @@ module XcodeArchiveCache
236
236
  dependency_remover.remove_dependency(prebuilt_node, dependent_target)
237
237
  end
238
238
 
239
- # @param [Xcodeproj::Project::Object::PBXNativeTarget] target
240
- #
241
- def find_build_configuration(target)
242
- build_configuration = target.build_configurations.select { |configuration| configuration.name == configuration_name }.first
243
- unless build_configuration
244
- raise Informative, "#{configuration_name} build configuration not found on target #{node.name}"
245
- end
246
-
247
- build_configuration
248
- end
249
-
250
239
  # @param [Xcodeproj::Project::Object::PBXNativeTarget] target
251
240
  #
252
241
  def get_pods_target_name(target)
@@ -44,7 +44,7 @@ module XcodeArchiveCache
44
44
  # @return [String]
45
45
  #
46
46
  def find_embed_frameworks_script(target, build_settings)
47
- find_script(target, build_settings, "[CP] Embed Pods Frameworks")
47
+ target.find_script(build_settings_interpolator, build_settings, "[CP] Embed Pods Frameworks")
48
48
  end
49
49
 
50
50
  # @param [Xcodeproj::Project::Object::PBXNativeTarget] target
@@ -53,25 +53,7 @@ module XcodeArchiveCache
53
53
  # @return [String]
54
54
  #
55
55
  def find_copy_resources_script(target, build_settings)
56
- find_script(target, build_settings, "[CP] Copy Pods Resources")
57
- end
58
-
59
- # @param [Xcodeproj::Project::Object::PBXNativeTarget] target
60
- # @param [XcodeArchiveCache::BuildSettings::Container] build_settings
61
- # @param [String] script_name
62
- #
63
- # @return [String]
64
- #
65
- def find_script(target, build_settings, script_name)
66
- target.shell_script_build_phases.each do |phase|
67
- if phase.display_name == script_name
68
- return build_settings_interpolator.interpolate(phase.shell_script, build_settings)
69
- .gsub(/^"|"$/, "")
70
- .strip
71
- end
72
- end
73
-
74
- nil
56
+ target.find_script(build_settings_interpolator, build_settings, "[CP] Copy Pods Resources")
75
57
  end
76
58
 
77
59
  # @param [String] file_path
@@ -0,0 +1,126 @@
1
+ module XcodeArchiveCache
2
+ module Injection
3
+ class PodsXCFrameworkFixer
4
+
5
+ include XcodeArchiveCache::Logs
6
+
7
+ # @param [XcodeArchiveCache::Injection::Storage] storage
8
+ # @param [XcodeArchive::BuildGraph::NativeTargetFinder] native_target_finder
9
+ # @param [String] configuration_name
10
+ #
11
+ def initialize(storage, native_target_finder, configuration_name)
12
+ @storage = storage
13
+ @native_target_finder = native_target_finder
14
+ @configuration_name = configuration_name
15
+ @shell_executor = XcodeArchiveCache::Shell::Executor.new
16
+ @build_settings_interpolator = XcodeArchiveCache::BuildSettings::StringInterpolator.new
17
+ @checked_targets = []
18
+ end
19
+
20
+ # @param [Xcodeproj::Project::Object::PBXAbstractTarget] target
21
+ # @param [XcodeArchiveCache::BuildSettings::Container] build_settings
22
+ #
23
+ def fix(target, build_settings_loader)
24
+ checked_targets.push(target.equatable_identifier)
25
+ build_settings = build_settings_loader.get_settings(target.project.path, target.display_name)
26
+
27
+ debug("fixing #{target.display_name}")
28
+ script_path = find_copy_xcframeworks_script(target, build_settings)
29
+ if script_path != nil
30
+ fix_file(script_path)
31
+
32
+ unless shell_executor.execute_with_env(script_path, build_settings.all)
33
+ raise XcodeArchiveCache::Informative, "Failed to execute Pods XCFramework script #{script_path}"
34
+ end
35
+ end
36
+
37
+ embed_frameworks_script_path = find_embed_frameworks_script(target, build_settings)
38
+ if embed_frameworks_script_path != nil
39
+ fix_file(embed_frameworks_script_path)
40
+ end
41
+
42
+ build_configuration = target.find_build_configuration(configuration_name)
43
+ if build_configuration.has_xcconfig?
44
+ fix_xcconfig_recursively(build_configuration.get_xcconfig_path, build_configuration.get_project_dir)
45
+ end
46
+
47
+ dependencies = native_target_finder.find_all_dependencies(target)
48
+ dependencies.each do |dependency_target|
49
+ if checked_targets.include?(dependency_target.equatable_identifier)
50
+ next
51
+ end
52
+
53
+ fix(dependency_target, build_settings_loader)
54
+ end
55
+ end
56
+
57
+ private
58
+
59
+ # @return [XcodeArchive::Injection::InjectionStorage]
60
+ #
61
+ attr_reader :storage
62
+
63
+ # @return [XcodeArchive::BuildGraph::NativeTargetFinder]
64
+ #
65
+ attr_reader :native_target_finder
66
+
67
+ # @return [String]
68
+ #
69
+ attr_reader :configuration_name
70
+
71
+ # @return [XcodeArchiveCache::Shell::Executor]
72
+ #
73
+ attr_reader :shell_executor
74
+
75
+ # @return [XcodeArchiveCache::BuildSettings::StringInterpolator]
76
+ #
77
+ attr_reader :build_settings_interpolator
78
+
79
+ # @return [Array<String>]
80
+ #
81
+ attr_accessor :checked_targets
82
+
83
+ # @param [String] path
84
+ # @param [String] project_dir
85
+ #
86
+ def fix_xcconfig_recursively(path, project_dir)
87
+ fix_file(path)
88
+ xcconfig = Xcodeproj::Config.new(path)
89
+
90
+ xcconfig.includes.each do |included_xcconfig|
91
+ included_xcconfig_path = File.join(project_dir, included_xcconfig)
92
+ fix_xcconfig_recursively(included_xcconfig_path, project_dir)
93
+ end
94
+ end
95
+
96
+ # @param [Xcodeproj::Project::Object::PBXAbstractTarget] target
97
+ # @param [XcodeArchiveCache::BuildSettings::Container] build_settings
98
+ #
99
+ # @return [String]
100
+ #
101
+ def find_copy_xcframeworks_script(target, build_settings)
102
+ target.find_script(build_settings_interpolator, build_settings, "[CP] Copy XCFrameworks")
103
+ end
104
+
105
+ # @param [Xcodeproj::Project::Object::PBXAbstractTarget] target
106
+ # @param [XcodeArchiveCache::BuildSettings::Container] build_settings
107
+ #
108
+ # @return [String]
109
+ #
110
+ def find_embed_frameworks_script(target, build_settings)
111
+ target.find_script(build_settings_interpolator, build_settings, "[CP] Embed Pods Frameworks")
112
+ end
113
+
114
+ # @param [String] file_path
115
+ #
116
+ def fix_file(file_path)
117
+ debug("fixing #{file_path}")
118
+ contents = File
119
+ .read(file_path)
120
+ .gsub("${PODS_XCFRAMEWORKS_BUILD_DIR}", storage.container_dir_path)
121
+
122
+ File.open(file_path, "w") {|file| file.puts(contents)}
123
+ end
124
+ end
125
+ end
126
+ end
data/lib/runner/runner.rb CHANGED
@@ -9,7 +9,7 @@ module XcodeArchiveCache
9
9
  @config = config
10
10
 
11
11
  projects = list_projects
12
- @native_target_finder = XcodeArchiveCache::BuildGraph::NativeTargetFinder.new(projects)
12
+ @native_target_finder = XcodeArchiveCache::BuildGraph::NativeTargetFinder.new(projects, config.active_configuration.build_configuration)
13
13
 
14
14
  storage_path = File.absolute_path(config.storage.path)
15
15
  @cache_storage = XcodeArchiveCache::ArtifactCache::LocalStorage.new(storage_path)
@@ -37,7 +37,7 @@ module XcodeArchiveCache
37
37
  return workspace.file_references.map {|file_reference| Xcodeproj::Project.open(file_reference.absolute_path(workspace_dir))}
38
38
  end
39
39
 
40
- raise Informative, "Configuration misses entry point -- must have either a project or a workspace"
40
+ raise XcodeArchiveCache::Informative, "Configuration misses entry point -- must have either a project or a workspace"
41
41
  end
42
42
 
43
43
  def run
@@ -65,7 +65,7 @@ module XcodeArchiveCache
65
65
  def handle_target(target_config)
66
66
  target = @native_target_finder.find_for_product_name(target_config.name)
67
67
  unless target
68
- raise Informative, "Target not found for #{target_config.name}"
68
+ raise XcodeArchiveCache::Informative, "Target not found for #{target_config.name}"
69
69
  end
70
70
 
71
71
  xcodebuild_executor = XcodeArchiveCache::Xcodebuild::Executor.new(config.active_configuration.build_configuration,
@@ -73,7 +73,8 @@ module XcodeArchiveCache
73
73
  config.settings.destination,
74
74
  config.active_configuration.action,
75
75
  config.active_configuration.xcodebuild_args)
76
- graph_builder = XcodeArchiveCache::BuildGraph::Builder.new(@native_target_finder, xcodebuild_executor)
76
+ build_settings_loader = XcodeArchiveCache::BuildSettings::Loader.new(xcodebuild_executor)
77
+ graph_builder = XcodeArchiveCache::BuildGraph::Builder.new(@native_target_finder, build_settings_loader)
77
78
 
78
79
  dependency_targets = Hash.new
79
80
  build_graphs = Hash.new
@@ -86,6 +87,9 @@ module XcodeArchiveCache
86
87
  build_graphs[dependency_name] = graph_builder.build_graph(target, dependency_target)
87
88
  end
88
89
 
90
+ pods_xcframeworks_fixer = XcodeArchiveCache::Injection::PodsXCFrameworkFixer.new(@injection_storage, @native_target_finder, config.active_configuration.build_configuration)
91
+ pods_xcframeworks_fixer.fix(target, build_settings_loader)
92
+
89
93
  target_config.dependencies.each do |dependency_name|
90
94
  info("processing #{dependency_name}")
91
95
 
@@ -107,7 +111,7 @@ module XcodeArchiveCache
107
111
  def find_dependency_target(target, dependency_name)
108
112
  dependency_target = @native_target_finder.find_for_product_name(dependency_name)
109
113
  unless dependency_target
110
- raise Informative, "Target not found for #{dependency_name} of #{target.display_name}"
114
+ raise XcodeArchiveCache::Informative, "Target not found for #{dependency_name} of #{target.display_name}"
111
115
  end
112
116
 
113
117
  dependency_target
@@ -12,7 +12,7 @@ module XcodeArchiveCache
12
12
  output, status = Open3.capture2e(actual_command)
13
13
 
14
14
  if status.exitstatus != 0
15
- raise Informative, "#{command}\nexecution failed\n#{output}"
15
+ raise XcodeArchiveCache::Informative, "#{command}\nexecution failed\n#{output}"
16
16
  end
17
17
 
18
18
  output
@@ -31,6 +31,18 @@ module XcodeArchiveCache
31
31
  result
32
32
  end
33
33
 
34
+ # @param [String] command
35
+ # @param [Hash] env
36
+ #
37
+ # @return [Boolean] true if command succeeded and returned 0, false otherwise
38
+ #
39
+ def execute_with_env(command, env)
40
+ result = system(env, "set -x && '#{command}'")
41
+
42
+ return false if result == nil
43
+ result
44
+ end
45
+
34
46
  private
35
47
 
36
48
  # @param [String] command
@@ -45,6 +45,7 @@ require 'injection/dependency_remover'
45
45
  require 'injection/headers_mover'
46
46
  require 'injection/storage'
47
47
  require 'injection/framework_embedder'
48
+ require 'injection/pods_xcframework_fixer'
48
49
 
49
50
  require 'modulemap/file_handler'
50
51
  require 'modulemap/header_path_extractor'
@@ -56,6 +57,9 @@ require 'shell/executor'
56
57
 
57
58
  require 'xcodebuild/executor'
58
59
 
60
+ require 'extensions/target'
61
+ require 'extensions/build_configuration'
62
+
59
63
  module XcodeArchiveCache
60
64
  class Informative < StandardError
61
65
  include CLAide::InformativeError
@@ -117,7 +117,7 @@ module XcodeArchiveCache
117
117
  #
118
118
  inferred_destination = action == ARCHIVE_ACTION ? GENERIC_DESTINATION : destination_by_platform
119
119
  if inferred_destination == nil
120
- raise Informative, "Destination not set for #{platform} platform"
120
+ raise XcodeArchiveCache::Informative, "Destination not set for #{platform} platform"
121
121
  end
122
122
 
123
123
  destination_specifier = inferred_destination == GENERIC_DESTINATION ? "generic/platform=#{platform}" : inferred_destination
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xcode-archive-cache
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.10
4
+ version: 0.0.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ilya Dyakonov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-08-31 00:00:00.000000000 Z
11
+ date: 2021-07-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: xcodeproj
@@ -36,20 +36,20 @@ dependencies:
36
36
  requirements:
37
37
  - - ">="
38
38
  - !ruby/object:Gem::Version
39
- version: '1.3'
39
+ version: '2.0'
40
40
  - - "<"
41
41
  - !ruby/object:Gem::Version
42
- version: '2.0'
42
+ version: '3.0'
43
43
  type: :runtime
44
44
  prerelease: false
45
45
  version_requirements: !ruby/object:Gem::Requirement
46
46
  requirements:
47
47
  - - ">="
48
48
  - !ruby/object:Gem::Version
49
- version: '1.3'
49
+ version: '2.0'
50
50
  - - "<"
51
51
  - !ruby/object:Gem::Version
52
- version: '2.0'
52
+ version: '3.0'
53
53
  - !ruby/object:Gem::Dependency
54
54
  name: xcpretty
55
55
  requirement: !ruby/object:Gem::Requirement
@@ -107,12 +107,15 @@ files:
107
107
  - lib/command/inject.rb
108
108
  - lib/config/config.rb
109
109
  - lib/config/dsl.rb
110
+ - lib/extensions/build_configuration.rb
111
+ - lib/extensions/target.rb
110
112
  - lib/injection/build_flags_changer.rb
111
113
  - lib/injection/dependency_remover.rb
112
114
  - lib/injection/framework_embedder.rb
113
115
  - lib/injection/headers_mover.rb
114
116
  - lib/injection/injector.rb
115
117
  - lib/injection/pods_script_fixer.rb
118
+ - lib/injection/pods_xcframework_fixer.rb
116
119
  - lib/injection/storage.rb
117
120
  - lib/logs/logs.rb
118
121
  - lib/modulemap/file_handler.rb
@@ -141,7 +144,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
141
144
  - !ruby/object:Gem::Version
142
145
  version: '0'
143
146
  requirements: []
144
- rubygems_version: 3.0.4
147
+ rubygems_version: 3.0.6
145
148
  signing_key:
146
149
  specification_version: 4
147
150
  summary: Native targets cache for Xcode archive builds.