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.
- checksums.yaml +4 -4
- data/lib/artifact_cache/archiver.rb +2 -1
- data/lib/artifact_cache/local_storage.rb +2 -1
- data/lib/build/performer.rb +1 -1
- data/lib/build/product_extractor.rb +92 -9
- data/lib/build_graph/builder.rb +10 -10
- data/lib/build_graph/native_target_finder.rb +123 -13
- data/lib/build_graph/node.rb +50 -2
- data/lib/build_graph/rebuild_evaluator.rb +30 -4
- data/lib/build_graph/sha_calculator.rb +22 -1
- data/lib/build_settings/extractor.rb +23 -1
- data/lib/build_settings/filter.rb +7 -3
- data/lib/build_settings/loader.rb +10 -1
- data/lib/build_settings/parser.rb +29 -6
- data/lib/build_settings/string_interpolator.rb +21 -5
- data/lib/config/config.rb +2 -2
- data/lib/extensions/build_configuration.rb +26 -0
- data/lib/extensions/target.rb +58 -0
- data/lib/injection/build_flags_changer.rb +176 -4
- data/lib/injection/dependency_remover.rb +22 -1
- data/lib/injection/headers_mover.rb +27 -3
- data/lib/injection/injector.rb +70 -33
- data/lib/injection/pods_script_fixer.rb +2 -20
- data/lib/injection/pods_xcframework_fixer.rb +126 -0
- data/lib/injection/storage.rb +47 -6
- data/lib/modulemap/file_handler.rb +20 -0
- data/lib/modulemap/header_path_extractor.rb +67 -0
- data/lib/modulemap/header_path_fixer.rb +65 -0
- data/lib/runner/runner.rb +39 -28
- data/lib/shell/executor.rb +15 -3
- data/lib/xcode-archive-cache.rb +8 -0
- data/lib/xcodebuild/executor.rb +5 -1
- metadata +18 -12
data/lib/build_graph/node.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
29
|
+
def find_all_entries(string)
|
30
|
+
return nil if string == nil
|
31
|
+
|
17
32
|
string.scan(setting_entry_regex)
|
18
|
-
.map {|entry|
|
19
|
-
.
|
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 [
|
67
|
+
# @return [Regexp]
|
49
68
|
#
|
50
|
-
def create_entry_regex(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
|
-
|
15
|
+
return nil if string == nil
|
16
|
+
|
17
|
+
entries = parser.find_all_entries(string)
|
16
18
|
result = string
|
17
19
|
|
18
|
-
|
19
|
-
value = build_settings[name]
|
20
|
+
entries.each do |entry|
|
21
|
+
value = build_settings[entry.name]
|
20
22
|
next unless value
|
21
23
|
|
22
|
-
|
23
|
-
result = result.gsub(
|
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
|