xcode-archive-cache 0.0.9 → 0.0.11
Sign up to get free protection for your applications and to get access to all the features.
- 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
|