xcode-archive-cache 0.0.9 → 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.
@@ -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
 
@@ -86,9 +91,52 @@ module XcodeArchiveCache
86
91
  # @return [String]
87
92
  #
88
93
  def dsym_file_name
89
- return nil unless build_settings
94
+ build_settings ? build_settings[XcodeArchiveCache::BuildSettings::DWARF_DSYM_FILE_NAME_KEY] : nil
95
+ end
96
+
97
+ # @return [String]
98
+ #
99
+ def original_modulemap_file_path
100
+ modulemap_file = modulemap_file_name
101
+ return unless modulemap_file
102
+
103
+ Pathname.new(modulemap_file).absolute? ? modulemap_file : File.join(File.dirname(native_target.project.path), modulemap_file)
104
+ end
105
+
106
+ # @return [String]
107
+ #
108
+ def resulting_modulemap_file_name
109
+ if module_name
110
+ module_name + ".modulemap"
111
+ else
112
+ File.basename(modulemap_file_name)
113
+ end
114
+ end
90
115
 
91
- build_settings[XcodeArchiveCache::BuildSettings::DWARF_DSYM_FILE_NAME_KEY]
116
+ # @return [String]
117
+ #
118
+ def swift_objc_interface_header_file
119
+ header_file = build_settings[XcodeArchiveCache::BuildSettings::SWIFT_OBJC_INTERFACE_HEADER_NAME_KEY]
120
+ if header_file == nil
121
+ our_module_name = module_name
122
+ return if our_module_name == nil
123
+
124
+ header_file = our_module_name + "-Swift.h"
125
+ end
126
+
127
+ header_file
128
+ end
129
+
130
+ # @return [String]
131
+ #
132
+ def module_name
133
+ build_settings[XcodeArchiveCache::BuildSettings::PRODUCT_MODULE_NAME_KEY]
134
+ end
135
+
136
+ # @return [String]
137
+ #
138
+ def modulemap_file_name
139
+ build_settings[XcodeArchiveCache::BuildSettings::MODULEMAP_FILE_KEY]
92
140
  end
93
141
 
94
142
  # @return [Array<Node>]
@@ -8,24 +8,50 @@ module XcodeArchiveCache
8
8
  @cache_storage = cache_storage
9
9
  end
10
10
 
11
+ # @param [XcodeArchiveCache::BuildGraph::Graph] graph
12
+ #
13
+ def evaluate_build_graph(graph)
14
+ return if graph.root_node.state != :unknown
15
+
16
+ # DFS over graph, evaluating dependencies first
17
+ #
18
+ stack = [graph.root_node]
19
+
20
+ while stack.length > 0
21
+ last_node = stack.last
22
+
23
+ if last_node.state == :evaluating_dependencies
24
+ # dependencies were evaluated, we're good to go
25
+ evaluate(last_node)
26
+ stack.delete_at(stack.length - 1)
27
+ elsif last_node.state == :unknown
28
+ last_node.state = :evaluating_dependencies
29
+ stack += last_node.dependencies.select { |dependency| dependency.state == :unknown }
30
+ else
31
+ stack.delete_at(stack.length - 1)
32
+ end
33
+ end
34
+ end
35
+
36
+ private
37
+
11
38
  # @param [XcodeArchiveCache::BuildGraph::Node] node
12
39
  #
13
40
  def evaluate(node)
14
- return if node.state != :unknown
41
+ has_dependencies_waiting_for_rebuild = node.dependencies
42
+ .reduce(false) { |rebuild, dependency| rebuild || dependency.waiting_for_rebuild }
15
43
 
16
44
  # we include dependency shas in every node sha calculation,
17
45
  # so if some dependency changes, that change propagates
18
46
  # all the way to the top level
19
47
  #
20
- if cache_storage.cached_artifact_path(node) == nil
48
+ if has_dependencies_waiting_for_rebuild || cache_storage.cached_artifact_path(node) == nil
21
49
  node.state = :waiting_for_rebuild
22
50
  else
23
51
  node.state = :exists_in_cache
24
52
  end
25
53
  end
26
54
 
27
- private
28
-
29
55
  # @return [XcodeArchiveCache::ArtifactCache::AbstractStorage]
30
56
  #
31
57
  attr_reader :cache_storage
@@ -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,6 +54,9 @@ module XcodeArchiveCache
36
54
  inputs << list_build_phase_inputs(build_phase)
37
55
  end
38
56
 
57
+ modulemap_file_path = node.original_modulemap_file_path
58
+ inputs << modulemap_file_path if modulemap_file_path
59
+
39
60
  # file path order should not affect evaluation result
40
61
  inputs.flatten.compact.sort
41
62
  end
@@ -71,7 +92,7 @@ module XcodeArchiveCache
71
92
  # @param [Array<String>] dependency_shas
72
93
  #
73
94
  def save_auxiliary_data(build_settings, dependency_shas, tempfile)
74
- file_contents = build_settings + dependency_shas.join("\n")
95
+ file_contents = build_settings + dependency_shas.join("\n") + "\nXCODE-ARCHIVE-CACHE: #{own_sha}\n"
75
96
  tempfile << file_contents
76
97
  tempfile.flush
77
98
  end
@@ -13,7 +13,7 @@ module XcodeArchiveCache
13
13
  # @return [Hash{String => Container}]
14
14
  # Target build settings keyed by target name
15
15
  #
16
- def extract_per_target(build_settings)
16
+ def extract_per_target(build_settings, fix_simulator)
17
17
  per_target_settings = build_settings.split("Build settings for action")
18
18
  result = Hash.new
19
19
 
@@ -22,6 +22,7 @@ module XcodeArchiveCache
22
22
  target_name = get_target_name(parsed_settings)
23
23
  next unless target_name
24
24
 
25
+ replace_platform_with_simulator(parsed_settings) if fix_simulator
25
26
  filtered_settings = filter.filter(parsed_settings)
26
27
  result[target_name] = Container.new(parsed_settings, filtered_settings)
27
28
  end
@@ -65,6 +66,27 @@ module XcodeArchiveCache
65
66
  result
66
67
  end
67
68
 
69
+
70
+ # @param [Hash{String => String}] settings
71
+ #
72
+ def replace_platform_with_simulator(settings)
73
+ original_platform = settings[EFFECTIVE_PLATFORM_NAME_KEY]
74
+ simulator_platform = settings[CORRESPONDING_SIMULATOR_PLATFORM_NAME_KEY]
75
+ settings[EFFECTIVE_PLATFORM_NAME_KEY] = "-#{simulator_platform}"
76
+ settings[PLATFORM_NAME_KEY] = simulator_platform
77
+
78
+ configuration = settings[CONFIGURATION_KEY]
79
+ path_regexp = Regexp.new("#{configuration}#{original_platform}")
80
+ simulator_path = "#{configuration}-#{simulator_platform}"
81
+ settings.each do |key, value|
82
+ settings[key] = value.gsub(path_regexp, simulator_path)
83
+ end
84
+ end
85
+
86
+ PLATFORM_NAME_KEY = "PLATFORM_NAME".freeze
87
+ EFFECTIVE_PLATFORM_NAME_KEY = "EFFECTIVE_PLATFORM_NAME".freeze
88
+ CORRESPONDING_SIMULATOR_PLATFORM_NAME_KEY = "CORRESPONDING_SIMULATOR_PLATFORM_NAME".freeze
89
+ CONFIGURATION_KEY = "CONFIGURATION".freeze
68
90
  TARGET_NAME_KEY = "TARGETNAME".freeze
69
91
 
70
92
  # @param [Hash{String => String}] parsed_settings
@@ -10,7 +10,7 @@ module XcodeArchiveCache
10
10
  # Machine-dependent settings i.e. paths, user names, group names are rejected
11
11
  #
12
12
  def filter(settings, settings_to_keep = SETTINGS_TO_KEEP)
13
- filtered_settings = settings.select {|name, _| settings_to_keep.include?(name)}
13
+ filtered_settings = settings.select { |name, _| settings_to_keep.include?(name) }
14
14
  SETTINGS_TO_STRIP.each do |name|
15
15
  value = filtered_settings[name]
16
16
  next if value == nil
@@ -44,7 +44,9 @@ module XcodeArchiveCache
44
44
  # splitting will be broken, but probability of
45
45
  # someone using such path is quite low (or it isn't ?)
46
46
  #
47
- value_components = value_without_quotes.split(/\s-/)
47
+ value_components = value_without_quotes
48
+ .split(/^-|\s-/)
49
+ .select { |component| component.length > 0 }
48
50
 
49
51
  index = 0
50
52
  indices_to_remove = []
@@ -66,7 +68,8 @@ module XcodeArchiveCache
66
68
  kept_components.push(component) unless indices_to_remove.include?(component_index)
67
69
  end
68
70
 
69
- kept_components.join(" -")
71
+ result = kept_components.join(" -")
72
+ result.length > 0 ? "-#{result}" : ""
70
73
  end
71
74
 
72
75
  # TODO: extend
@@ -283,6 +286,7 @@ module XcodeArchiveCache
283
286
  output-file-map
284
287
  save-optimization-record-path
285
288
  working-directory
289
+ fmodule-map-file
286
290
  )
287
291
  end
288
292
  end
@@ -1,8 +1,15 @@
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
8
+ MODULEMAP_FILE_KEY = "MODULEMAP_FILE".freeze
9
+ SWIFT_OBJC_INTERFACE_HEADER_NAME_KEY = "SWIFT_OBJC_INTERFACE_HEADER_NAME".freeze
10
+ SWIFT_MODULE_NAME_KEY = "SWIFT_MODULE_NAME".freeze
11
+ PRODUCT_MODULE_NAME_KEY = "PRODUCT_MODULE_NAME".freeze
12
+ DERIVED_SOURCES_DIR_KEY = "DERIVED_SOURCES_DIR".freeze
6
13
 
7
14
  class Container
8
15
 
@@ -58,9 +65,11 @@ module XcodeArchiveCache
58
65
  end
59
66
  end
60
67
 
68
+ should_fix_settings = executor.set_up_for_simulator?
69
+
61
70
  threads.each do |thread|
62
71
  project_path, all_targets_settings = thread.value
63
- per_target_settings = extractor.extract_per_target(all_targets_settings)
72
+ per_target_settings = extractor.extract_per_target(all_targets_settings, should_fix_settings)
64
73
  set_project_settings(project_path, per_target_settings)
65
74
  end
66
75
  end
@@ -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
@@ -45,9 +64,9 @@ module XcodeArchiveCache
45
64
 
46
65
  # @param [String] characters
47
66
  #
48
- # @return [String]
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