xcode-archive-cache 0.0.8.pre.2 → 0.0.10
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 +88 -5
- data/lib/build_graph/builder.rb +5 -1
- data/lib/build_graph/native_target_finder.rb +46 -11
- 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 +21 -1
- data/lib/build_settings/filter.rb +7 -3
- data/lib/build_settings/loader.rb +8 -1
- data/lib/build_settings/parser.rb +1 -1
- data/lib/injection/build_flags_changer.rb +173 -4
- data/lib/injection/dependency_remover.rb +22 -1
- data/lib/injection/headers_mover.rb +27 -3
- data/lib/injection/injector.rb +69 -20
- 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 +31 -24
- data/lib/shell/executor.rb +2 -2
- data/lib/xcode-archive-cache.rb +4 -0
- data/lib/xcodebuild/executor.rb +4 -0
- metadata +32 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ff86c853bc7b50f265964695cd55edd14821c821f5d27a1f916dcc23ccc1c4b4
|
4
|
+
data.tar.gz: a11e6dd9c98f59526f6f5329aab00acdcc58b5d7e2b65d83b6a1348d647a2323
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a71f194f4af63d93ee4f256977eb98525065599a36f270215c5c0f3a18cb8742957bb8f2e407497a7629f05ba18b9532d093d02b1dec305fcf4f82f815473431
|
7
|
+
data.tar.gz: ba25058d81d37e12594422d9a765d07fb8af192b53fe980ca3b4da3e1eac61f5a0bc69454f406be92094742e7809dbe8f4887d33e48b305c869733e5c581a4d8
|
@@ -9,7 +9,8 @@ module XcodeArchiveCache
|
|
9
9
|
#
|
10
10
|
def archive(path, destination)
|
11
11
|
if File.exists?(destination)
|
12
|
-
|
12
|
+
warn "Replacing artifact archive at path #{destination}"
|
13
|
+
FileUtils.rm_rf(destination)
|
13
14
|
end
|
14
15
|
|
15
16
|
if File.file?(path)
|
@@ -60,7 +60,8 @@ module XcodeArchiveCache
|
|
60
60
|
state_file_path = archive_path + ".state"
|
61
61
|
|
62
62
|
if File.exist?(state_file_path)
|
63
|
-
|
63
|
+
warn "Replacing state file #{state_file_path}"
|
64
|
+
FileUtils.rm_f(state_file_path)
|
64
65
|
end
|
65
66
|
|
66
67
|
dependency_shas = node.dependencies
|
data/lib/build/performer.rb
CHANGED
@@ -2,6 +2,8 @@ module XcodeArchiveCache
|
|
2
2
|
module Build
|
3
3
|
class ProductExtractor
|
4
4
|
|
5
|
+
include XcodeArchiveCache::Logs
|
6
|
+
|
5
7
|
# @param [String] configuration
|
6
8
|
# @param [String] derived_data_path
|
7
9
|
#
|
@@ -17,7 +19,9 @@ module XcodeArchiveCache
|
|
17
19
|
#
|
18
20
|
def list_product_contents(built_node)
|
19
21
|
file_paths = list_products(built_node)
|
20
|
-
file_paths
|
22
|
+
file_paths
|
23
|
+
.select { |path| File.exist?(path) }
|
24
|
+
.map { |path| File.realpath(path) }
|
21
25
|
end
|
22
26
|
|
23
27
|
private
|
@@ -78,7 +82,39 @@ module XcodeArchiveCache
|
|
78
82
|
raise Informative, "Product of type #{built_node.native_target.product_type} not found for #{built_node.name}"
|
79
83
|
end
|
80
84
|
|
81
|
-
[product_path]
|
85
|
+
paths = [product_path]
|
86
|
+
|
87
|
+
# this one is generated during Swift compilation
|
88
|
+
# so we need to cache it as well
|
89
|
+
#
|
90
|
+
swift_objc_interface_header_glob = get_swift_objc_interface_header_glob(built_node)
|
91
|
+
swift_objc_interface_header_path = Dir.glob(swift_objc_interface_header_glob).first
|
92
|
+
if swift_objc_interface_header_path
|
93
|
+
debug("using Swift-ObjC interface header #{swift_objc_interface_header_path}")
|
94
|
+
paths << swift_objc_interface_header_path
|
95
|
+
end
|
96
|
+
|
97
|
+
swiftmodule_glob = get_swiftmodule_glob(built_node)
|
98
|
+
if swiftmodule_glob
|
99
|
+
swiftmodule_path = Dir.glob(swiftmodule_glob).first
|
100
|
+
|
101
|
+
if swiftmodule_path
|
102
|
+
debug("using swiftmodule #{swiftmodule_path}")
|
103
|
+
paths << swiftmodule_path
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
modulemap_glob = get_modulemap_glob(built_node)
|
108
|
+
if modulemap_glob
|
109
|
+
modulemap_path = Dir.glob(modulemap_glob).first
|
110
|
+
|
111
|
+
if modulemap_path
|
112
|
+
debug("using modulemap #{modulemap_path}")
|
113
|
+
paths << modulemap_path
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
paths
|
82
118
|
end
|
83
119
|
|
84
120
|
# @param [XcodeArchiveCache::BuildGraph::Node] built_node
|
@@ -89,9 +125,52 @@ module XcodeArchiveCache
|
|
89
125
|
product_name = built_node.native_target.product_reference.name ?
|
90
126
|
built_node.native_target.product_reference.name :
|
91
127
|
built_node.native_target.product_reference.path
|
128
|
+
get_product_glob(File.basename(product_name))
|
129
|
+
end
|
130
|
+
|
131
|
+
# @param [XcodeArchiveCache::BuildGraph::Node] built_node
|
132
|
+
#
|
133
|
+
# @return [String]
|
134
|
+
#
|
135
|
+
def get_swift_objc_interface_header_glob(built_node)
|
136
|
+
get_product_glob(File.basename(built_node.swift_objc_interface_header_file))
|
137
|
+
end
|
138
|
+
|
139
|
+
# @param [XcodeArchiveCache::BuildGraph::Node] built_node
|
140
|
+
#
|
141
|
+
# @return [String]
|
142
|
+
#
|
143
|
+
def get_swiftmodule_glob(built_node)
|
144
|
+
if built_node.module_name
|
145
|
+
get_product_glob(built_node.module_name + ".swiftmodule")
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
# @param [XcodeArchiveCache::BuildGraph::Node] built_node
|
150
|
+
#
|
151
|
+
# @return [String]
|
152
|
+
#
|
153
|
+
def get_modulemap_glob(built_node)
|
154
|
+
resulting_modulemap_file_name = built_node.resulting_modulemap_file_name
|
155
|
+
if resulting_modulemap_file_name
|
156
|
+
get_product_glob(resulting_modulemap_file_name)
|
157
|
+
else
|
158
|
+
modulemap_file_path = built_node.original_modulemap_file_path
|
159
|
+
if modulemap_file_path && File.exist?(modulemap_file_path)
|
160
|
+
modulemap_file_name = File.basename(modulemap_file_path)
|
161
|
+
get_product_glob(modulemap_file_name)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
# @param [String] file_name
|
167
|
+
#
|
168
|
+
# @return [String]
|
169
|
+
#
|
170
|
+
def get_product_glob(file_name)
|
92
171
|
File.join(derived_data_path,
|
93
172
|
"**",
|
94
|
-
|
173
|
+
file_name)
|
95
174
|
end
|
96
175
|
|
97
176
|
# @param [String] framework_path
|
@@ -106,7 +185,7 @@ module XcodeArchiveCache
|
|
106
185
|
end
|
107
186
|
|
108
187
|
uuids = list_bc_symbolmap_uuids(executable_path)
|
109
|
-
uuids.map {|uuid| find_bc_symbolmap(uuid)}.flatten
|
188
|
+
uuids.map { |uuid| find_bc_symbolmap(uuid) }.flatten
|
110
189
|
end
|
111
190
|
|
112
191
|
# @param [String] executable_path
|
@@ -114,7 +193,11 @@ module XcodeArchiveCache
|
|
114
193
|
# @return [Array<String>]
|
115
194
|
#
|
116
195
|
def list_bc_symbolmap_uuids(executable_path)
|
117
|
-
|
196
|
+
begin
|
197
|
+
shell_executor.execute_for_output("otool -l #{executable_path} | grep uuid | awk {'print $2'}").split("\n")
|
198
|
+
rescue
|
199
|
+
[]
|
200
|
+
end
|
118
201
|
end
|
119
202
|
|
120
203
|
# @param [String] uuid
|
data/lib/build_graph/builder.rb
CHANGED
@@ -67,7 +67,11 @@ module XcodeArchiveCache
|
|
67
67
|
node = ALL_NODES.select {|node| node.native_target.uuid == target.uuid && node.native_target.project == target.project}.first
|
68
68
|
if node
|
69
69
|
debug("already traversed this one")
|
70
|
-
|
70
|
+
unless graph.nodes.include?(node)
|
71
|
+
nodes_to_add = node.subgraph.select {|subgraph_node| !graph.nodes.include?(subgraph_node)}
|
72
|
+
graph.add_multiple_nodes(nodes_to_add)
|
73
|
+
end
|
74
|
+
|
71
75
|
return node
|
72
76
|
else
|
73
77
|
debug("adding new node")
|
@@ -5,13 +5,22 @@ module XcodeArchiveCache
|
|
5
5
|
# @param [Array<Xcodeproj::Project>] projects
|
6
6
|
#
|
7
7
|
def initialize(projects)
|
8
|
-
@all_targets = projects
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
8
|
+
@all_targets = extract_targets(projects)
|
9
|
+
end
|
10
|
+
|
11
|
+
# @param [Array<Xcodeproj::Project>] projects
|
12
|
+
#
|
13
|
+
# @return [Array<Xcodeproj::Project::Object::PBXNativeTarget>]
|
14
|
+
#
|
15
|
+
def extract_targets(projects)
|
16
|
+
projects
|
17
|
+
.map {|project| unnest(project)}
|
18
|
+
.flatten
|
19
|
+
.sort_by(&:path)
|
20
|
+
.inject([]) {|unique, current| unique.last && unique.last.path == current.path ? unique : unique + [current]}
|
21
|
+
.map(&:native_targets)
|
22
|
+
.flatten
|
23
|
+
.select {|target| !target.test_target_type?}
|
15
24
|
end
|
16
25
|
|
17
26
|
# @param [String] platform_name
|
@@ -36,9 +45,26 @@ module XcodeArchiveCache
|
|
36
45
|
#
|
37
46
|
def find_for_file(file)
|
38
47
|
if file.file_ref.is_a?(Xcodeproj::Project::Object::PBXReferenceProxy)
|
39
|
-
project = file.file_ref.remote_ref.container_portal_object
|
40
48
|
product_reference_uuid = file.file_ref.remote_ref.remote_global_id_string
|
41
|
-
find_with_product_ref_uuid(
|
49
|
+
target = find_with_product_ref_uuid(product_reference_uuid)
|
50
|
+
if target == nil
|
51
|
+
project = file.file_ref.remote_ref.container_portal_object
|
52
|
+
target = find_in_project(project, product_reference_uuid)
|
53
|
+
|
54
|
+
# allow all targets from this project
|
55
|
+
# to be linked to that exact project
|
56
|
+
#
|
57
|
+
# otherwise, injection will operate on different Xcodeproj::Project objects
|
58
|
+
# resulting to only the last target being actually removed
|
59
|
+
#
|
60
|
+
@all_targets += extract_targets([project])
|
61
|
+
end
|
62
|
+
|
63
|
+
if target == nil
|
64
|
+
raise Informative, "Target for #{file.file_ref.path} not found"
|
65
|
+
end
|
66
|
+
|
67
|
+
target
|
42
68
|
elsif file.file_ref.is_a?(Xcodeproj::Project::Object::PBXFileReference)
|
43
69
|
# products of sibling project targets are added as PBXFileReferences
|
44
70
|
targets = find_with_product_path(file.file_ref.path)
|
@@ -54,7 +80,7 @@ module XcodeArchiveCache
|
|
54
80
|
#
|
55
81
|
def find_for_product_name(product_name)
|
56
82
|
all_targets.select {|native_target| native_target.name == product_name || native_target.product_reference.display_name == product_name}
|
57
|
-
|
83
|
+
.first
|
58
84
|
end
|
59
85
|
|
60
86
|
private
|
@@ -85,7 +111,16 @@ module XcodeArchiveCache
|
|
85
111
|
#
|
86
112
|
# @return [Xcodeproj::Project::Object::PBXNativeTarget]
|
87
113
|
#
|
88
|
-
def find_with_product_ref_uuid(
|
114
|
+
def find_with_product_ref_uuid(uuid)
|
115
|
+
all_targets.select {|target| target.product_reference.uuid == uuid}.first
|
116
|
+
end
|
117
|
+
|
118
|
+
# @param [Xcodeproj::Project] project
|
119
|
+
# @param [String] uuid
|
120
|
+
#
|
121
|
+
# @return [Xcodeproj::Project::Object::PBXNativeTarget]
|
122
|
+
#
|
123
|
+
def find_in_project(project, uuid)
|
89
124
|
project.native_targets.select {|target| target.product_reference.uuid == uuid}.first
|
90
125
|
end
|
91
126
|
|
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
|