xcode-archive-cache 0.0.10 → 0.0.11

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