xcode-archive-cache 0.0.8.pre.2 → 0.0.10

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 52f8f43f53d74aef2d09148fe876d585c3cacf6f8f280a493684e235fb718d7f
4
- data.tar.gz: 71df654b2b3d8e4bc867357b83e86bf6f2aea403f9d15c2552bdefe1d3688331
3
+ metadata.gz: ff86c853bc7b50f265964695cd55edd14821c821f5d27a1f916dcc23ccc1c4b4
4
+ data.tar.gz: a11e6dd9c98f59526f6f5329aab00acdcc58b5d7e2b65d83b6a1348d647a2323
5
5
  SHA512:
6
- metadata.gz: a2e2ebc240b6ec293000cc023e65ed11a563ba841cb3dfafbab7e8d1ceaae0d9a21d2d9d0b556ff450495be9f20384adb27b34f68614f716aedf1e1aab9c28e4
7
- data.tar.gz: 472d0209a2a24f01c8f07a7e33bdafbd85d915dbfd358f1f0799ca47ba3b34456f11d09ba67bc38874b95452f8e88d2e6540ae3ed5ab654a9cc6206a5d51cc64
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
- raise ArgumentError.new, "Artifact cache path #{destination} is already taken"
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
- raise ArgumentError.new, "State file already exists: #{state_file_path}"
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
@@ -35,7 +35,7 @@ module XcodeArchiveCache
35
35
  # @param [XcodeArchiveCache::BuildGraph::Graph] graph
36
36
  #
37
37
  def should_rebuild?(graph)
38
- graph.nodes.reduce(false) {|rebuild, node| rebuild || node.waiting_for_rebuild}
38
+ graph.root_node.state != :unpacked
39
39
  end
40
40
 
41
41
  private
@@ -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.select {|path| File.exist?(path)}.map {|path| File.realpath(path)}
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
- File.basename(product_name))
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
- shell_executor.execute_for_output("otool -l #{executable_path} | grep uuid | awk {'print $2'}").split("\n")
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
@@ -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
- graph.add_multiple_nodes(node.subgraph) unless graph.nodes.include?(node)
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
- .map {|project| unnest(project)}
10
- .flatten
11
- .uniq
12
- .map(&:native_targets)
13
- .flatten
14
- .select {|target| !target.test_target_type? }
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(project, product_reference_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
- .first
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(project, 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
 
@@ -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