kintsugi 0.6.3 → 0.7.0
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/.github/workflows/release.yml +1 -1
- data/.github/workflows/tests.yml +1 -1
- data/README.md +10 -0
- data/assets/interactive-conflict-resolution.png +0 -0
- data/kintsugi.gemspec +1 -0
- data/lib/kintsugi/apply_change_to_project.rb +204 -122
- data/lib/kintsugi/cli.rb +25 -8
- data/lib/kintsugi/conflict_resolver.rb +130 -0
- data/lib/kintsugi/merge.rb +7 -4
- data/lib/kintsugi/settings.rb +8 -0
- data/lib/kintsugi/version.rb +1 -1
- data/lib/kintsugi/xcodeproj_extensions.rb +49 -1
- data/spec/kintsugi_apply_change_to_project_spec.rb +605 -113
- data/spec/kintsugi_integration_spec.rb +2 -1
- metadata +19 -3
@@ -4,10 +4,11 @@
|
|
4
4
|
|
5
5
|
require "xcodeproj"
|
6
6
|
|
7
|
-
require_relative "
|
7
|
+
require_relative "conflict_resolver"
|
8
8
|
require_relative "error"
|
9
9
|
require_relative "settings"
|
10
10
|
require_relative "xcodeproj_extensions"
|
11
|
+
require_relative "utils"
|
11
12
|
|
12
13
|
class Array
|
13
14
|
# Converts an array of arrays of size 2 into a multimap, mapping the first element of each
|
@@ -33,10 +34,18 @@ module Kintsugi
|
|
33
34
|
# Xcodeproj::Differ#project_diff where its `key_1` and `key_2` parameters have values of
|
34
35
|
# `:added` and `:removed` respectively.
|
35
36
|
#
|
37
|
+
# @param [Xcodeproj::Project] change_source_project
|
38
|
+
# Project from which `change` to apply was created. Used for providing information about
|
39
|
+
# components that are no longer available in `project`.
|
40
|
+
|
36
41
|
# @return [void]
|
37
|
-
def apply_change_to_project(project, change)
|
42
|
+
def apply_change_to_project(project, change, change_source_project)
|
38
43
|
return unless change&.key?("rootObject")
|
39
44
|
|
45
|
+
@change_source_project = change_source_project
|
46
|
+
@ignored_components_group_paths = []
|
47
|
+
@created_components_group_paths = []
|
48
|
+
|
40
49
|
# We iterate over the main group and project references first because they might create file
|
41
50
|
# or project references that are referenced in other parts.
|
42
51
|
unless change["rootObject"]["mainGroup"].nil?
|
@@ -96,17 +105,23 @@ module Kintsugi
|
|
96
105
|
entries + group_entries
|
97
106
|
end
|
98
107
|
|
99
|
-
def apply_group_additions(project, additions)
|
108
|
+
def apply_group_additions(project, additions, force_create_containing_group: false)
|
100
109
|
additions.each do |change, path|
|
101
110
|
next unless %w[PBXGroup PBXVariantGroup].include?(change["isa"])
|
102
111
|
|
103
112
|
group_type = Module.const_get("Xcodeproj::Project::#{change["isa"]}")
|
104
|
-
containing_group =
|
113
|
+
containing_group = project.group_or_file_at_path(path)
|
105
114
|
|
106
115
|
if containing_group.nil?
|
107
|
-
|
108
|
-
|
109
|
-
|
116
|
+
display_name = change["displayName"]
|
117
|
+
if !force_create_containing_group &&
|
118
|
+
!ConflictResolver.create_nonexistent_group_when_adding_subgroup?(path, display_name)
|
119
|
+
@ignored_components_group_paths.append(join_path(path, display_name))
|
120
|
+
next
|
121
|
+
end
|
122
|
+
|
123
|
+
@created_components_group_paths.append(join_path(path, display_name))
|
124
|
+
containing_group = create_nonexistent_groupable_component(project, path)
|
110
125
|
end
|
111
126
|
|
112
127
|
next if !Settings.allow_duplicates &&
|
@@ -127,7 +142,7 @@ module Kintsugi
|
|
127
142
|
end
|
128
143
|
end
|
129
144
|
|
130
|
-
def apply_file_changes(project, additions, removals)
|
145
|
+
def apply_file_changes(project, additions, removals, force_create_containing_group: false)
|
131
146
|
def file_reference_key(change)
|
132
147
|
[change["name"], change["path"], change["sourceTree"]]
|
133
148
|
end
|
@@ -147,13 +162,19 @@ module Kintsugi
|
|
147
162
|
end.to_h
|
148
163
|
|
149
164
|
file_additions.each do |change, path|
|
150
|
-
containing_group =
|
165
|
+
containing_group = project.group_or_file_at_path(path)
|
151
166
|
change_key = file_reference_key(change)
|
152
167
|
|
153
168
|
if containing_group.nil?
|
154
|
-
|
155
|
-
|
156
|
-
|
169
|
+
if !force_create_containing_group &&
|
170
|
+
!ConflictResolver.create_nonexistent_group_when_adding_file?(path,
|
171
|
+
change["displayName"])
|
172
|
+
@ignored_components_group_paths.append(join_path(path, change["displayName"]))
|
173
|
+
next
|
174
|
+
end
|
175
|
+
|
176
|
+
@created_components_group_paths.append(join_path(path, change["displayName"]))
|
177
|
+
containing_group = create_nonexistent_groupable_component(project, path)
|
157
178
|
end
|
158
179
|
|
159
180
|
if (removal_keys_to_references[change_key] || []).empty?
|
@@ -194,9 +215,17 @@ module Kintsugi
|
|
194
215
|
|
195
216
|
def apply_group_and_file_diffs(project, diffs)
|
196
217
|
diffs.each do |change, path|
|
197
|
-
component = project
|
218
|
+
component = project.group_or_file_at_path(path)
|
219
|
+
|
220
|
+
if component.nil? && change&.keys != ["children"]
|
221
|
+
unless ConflictResolver.create_nonexistent_component_when_changing_it?(path)
|
222
|
+
@ignored_components_group_paths.append(path)
|
223
|
+
next
|
224
|
+
end
|
198
225
|
|
199
|
-
|
226
|
+
@created_components_group_paths.append(path)
|
227
|
+
component = create_nonexistent_groupable_component(project, path)
|
228
|
+
end
|
200
229
|
|
201
230
|
change.each do |subchange_name, subchange|
|
202
231
|
next if subchange_name == "children"
|
@@ -206,6 +235,25 @@ module Kintsugi
|
|
206
235
|
end
|
207
236
|
end
|
208
237
|
|
238
|
+
def create_nonexistent_groupable_component(project, path)
|
239
|
+
source_project_component = @change_source_project.group_or_file_at_path(path)
|
240
|
+
component_change = source_project_component.to_tree_hash
|
241
|
+
containing_group_path = parent_group_path(path)
|
242
|
+
|
243
|
+
case source_project_component
|
244
|
+
when Xcodeproj::Project::PBXFileReference
|
245
|
+
apply_file_changes(project, [[component_change, containing_group_path]], [],
|
246
|
+
force_create_containing_group: true)
|
247
|
+
when Xcodeproj::Project::PBXGroup
|
248
|
+
apply_group_additions(project, [[component_change, containing_group_path]],
|
249
|
+
force_create_containing_group: true)
|
250
|
+
else
|
251
|
+
raise MergeError, "Component should either be a group or a file reference. " \
|
252
|
+
"Instead got: #{source_project_component}"
|
253
|
+
end
|
254
|
+
project.group_or_file_at_path(path)
|
255
|
+
end
|
256
|
+
|
209
257
|
def apply_group_removals(project, removals)
|
210
258
|
removals.sort_by(&:last).reverse.each do |change, path|
|
211
259
|
next unless %w[PBXGroup PBXVariantGroup].include?(change["isa"])
|
@@ -236,7 +284,7 @@ module Kintsugi
|
|
236
284
|
component = replace_component_with_new_type(parent_component, attribute_name, change)
|
237
285
|
change = change_for_component_of_new_type(component, change)
|
238
286
|
else
|
239
|
-
component = child_component(parent_component,
|
287
|
+
component = child_component(parent_component, change_name)
|
240
288
|
end
|
241
289
|
|
242
290
|
if change[:removed].is_a?(Hash)
|
@@ -244,8 +292,7 @@ module Kintsugi
|
|
244
292
|
elsif change[:removed].is_a?(Array)
|
245
293
|
unless component.nil?
|
246
294
|
(change[:removed]).each do |removed_change|
|
247
|
-
child = child_component_of_object_list(component, removed_change
|
248
|
-
removed_change["displayName"])
|
295
|
+
child = child_component_of_object_list(component, removed_change["displayName"])
|
249
296
|
remove_component(child, removed_change)
|
250
297
|
end
|
251
298
|
end
|
@@ -255,6 +302,7 @@ module Kintsugi
|
|
255
302
|
|
256
303
|
if change[:added].is_a?(Hash)
|
257
304
|
add_child_to_component(parent_component, change[:added], change_path)
|
305
|
+
component = child_component(parent_component, change_name)
|
258
306
|
elsif change[:added].is_a?(Array)
|
259
307
|
(change[:added]).each do |added_change|
|
260
308
|
add_child_to_component(parent_component, added_change, change_path)
|
@@ -265,15 +313,58 @@ module Kintsugi
|
|
265
313
|
|
266
314
|
subchanges_of_change(change).each do |subchange_name, subchange|
|
267
315
|
if component.nil?
|
268
|
-
|
269
|
-
|
270
|
-
"conflict that should be resolved manually."
|
316
|
+
component = resolve_nonexistent_component(parent_component, change_path)
|
317
|
+
break if component.nil?
|
271
318
|
end
|
272
319
|
|
273
320
|
apply_change_to_component(component, subchange_name, subchange, change_path)
|
274
321
|
end
|
275
322
|
end
|
276
323
|
|
324
|
+
def resolve_nonexistent_component(parent_component, change_path)
|
325
|
+
source_project_component = component_at_path(@change_source_project, change_path)
|
326
|
+
group_path = group_path_of_group_based_component(source_project_component)
|
327
|
+
|
328
|
+
if group_path
|
329
|
+
should_create_component = @created_components_group_paths.include?(group_path) ||
|
330
|
+
(!@ignored_components_group_paths.include?(group_path) &&
|
331
|
+
!ConflictResolver.create_nonexistent_component_when_changing_it?(change_path))
|
332
|
+
return unless should_create_component
|
333
|
+
elsif !ConflictResolver.create_nonexistent_component_when_changing_it?(change_path)
|
334
|
+
return
|
335
|
+
end
|
336
|
+
|
337
|
+
non_object_list_parent =
|
338
|
+
if parent_component.is_a?(Xcodeproj::Project::ObjectList)
|
339
|
+
parent_component.owner
|
340
|
+
else
|
341
|
+
parent_component
|
342
|
+
end
|
343
|
+
add_child_to_component(non_object_list_parent, source_project_component.to_tree_hash,
|
344
|
+
change_path)
|
345
|
+
component_at_path(non_object_list_parent.project, change_path)
|
346
|
+
end
|
347
|
+
|
348
|
+
def group_path_of_group_based_component(component)
|
349
|
+
if component.is_a?(Xcodeproj::Project::PBXBuildFile) && !component.file_ref.nil?
|
350
|
+
component.file_ref.hierarchy_path.delete_prefix("/")
|
351
|
+
elsif component.is_a?(Xcodeproj::Project::PBXFileReference) ||
|
352
|
+
component.is_a?(Xcodeproj::Project::PBXGroup)
|
353
|
+
component.hierarchy_path.delete_prefix("/")
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
def component_at_path(project, path)
|
358
|
+
current_component = project
|
359
|
+
until path["/"].nil?
|
360
|
+
change_name = path.split("/")[0]
|
361
|
+
current_component = child_component(current_component, change_name)
|
362
|
+
path = path.delete_prefix("#{change_name}/")
|
363
|
+
end
|
364
|
+
|
365
|
+
child_component(current_component, path)
|
366
|
+
end
|
367
|
+
|
277
368
|
def subchanges_of_change(change)
|
278
369
|
if change.key?(:diff)
|
279
370
|
change[:diff]
|
@@ -341,21 +432,17 @@ module Kintsugi
|
|
341
432
|
end
|
342
433
|
end
|
343
434
|
|
344
|
-
def child_component(component,
|
435
|
+
def child_component(component, change_name)
|
345
436
|
if component.is_a?(Xcodeproj::Project::ObjectList)
|
346
|
-
child_component_of_object_list(component,
|
437
|
+
child_component_of_object_list(component, change_name)
|
347
438
|
else
|
348
439
|
attribute_name = attribute_name_from_change_name(change_name)
|
349
440
|
component.send(attribute_name)
|
350
441
|
end
|
351
442
|
end
|
352
443
|
|
353
|
-
def child_component_of_object_list(component,
|
354
|
-
|
355
|
-
find_reference_proxy_in_component(component, change["remoteRef"])
|
356
|
-
else
|
357
|
-
component.find { |child| child.display_name == change_name }
|
358
|
-
end
|
444
|
+
def child_component_of_object_list(component, change_name)
|
445
|
+
component.find { |child| child.display_name == change_name }
|
359
446
|
end
|
360
447
|
|
361
448
|
def simple_attribute?(component, attribute_name)
|
@@ -366,18 +453,20 @@ module Kintsugi
|
|
366
453
|
|
367
454
|
def apply_change_to_simple_attribute(component, attribute_name, change)
|
368
455
|
new_attribute_value =
|
369
|
-
simple_attribute_value_with_change(component.send(attribute_name), change)
|
456
|
+
simple_attribute_value_with_change(component.send(attribute_name), change, attribute_name)
|
370
457
|
component.send("#{attribute_name}=", new_attribute_value)
|
371
458
|
end
|
372
459
|
|
373
|
-
def simple_attribute_value_with_change(old_value, change)
|
460
|
+
def simple_attribute_value_with_change(old_value, change, attribute_name)
|
374
461
|
type = simple_attribute_type(old_value, change[:removed], change[:added])
|
375
|
-
new_value = new_simple_attribute_value(type, old_value, change[:removed], change[:added]
|
462
|
+
new_value = new_simple_attribute_value(type, old_value, change[:removed], change[:added],
|
463
|
+
attribute_name)
|
376
464
|
|
377
465
|
subchanges_of_change(change).each do |subchange_name, subchange_value|
|
378
466
|
new_value = new_value || old_value || {}
|
379
467
|
new_value[subchange_name] =
|
380
|
-
simple_attribute_value_with_change(old_value[subchange_name], subchange_value
|
468
|
+
simple_attribute_value_with_change(old_value[subchange_name], subchange_value,
|
469
|
+
subchange_name)
|
381
470
|
end
|
382
471
|
|
383
472
|
new_value
|
@@ -389,71 +478,87 @@ module Kintsugi
|
|
389
478
|
if types.include?(Hash)
|
390
479
|
unless types.to_set.subset?([Hash, NilClass].to_set)
|
391
480
|
raise MergeError, "Cannot apply changes because the types are not compatible. Existing " \
|
392
|
-
|
393
|
-
|
481
|
+
"value: '#{old_value}', removed change: '#{removed_change}', added " \
|
482
|
+
"change: '#{added_change}'"
|
394
483
|
end
|
395
484
|
Hash
|
396
485
|
elsif types.include?(Array)
|
397
486
|
unless types.to_set.subset?([Array, String, NilClass].to_set)
|
398
487
|
raise MergeError, "Cannot apply changes because the types are not compatible. Existing " \
|
399
|
-
|
400
|
-
|
488
|
+
"value: '#{old_value}', removed change: '#{removed_change}', added " \
|
489
|
+
"change: '#{added_change}'"
|
401
490
|
end
|
402
491
|
Array
|
403
492
|
elsif types.include?(String)
|
404
493
|
unless types.to_set.subset?([String, NilClass].to_set)
|
405
494
|
raise MergeError, "Cannot apply changes because the types are not compatible. Existing " \
|
406
|
-
|
407
|
-
|
495
|
+
"value: '#{old_value}', removed change: '#{removed_change}', added " \
|
496
|
+
"change: '#{added_change}'"
|
408
497
|
end
|
409
498
|
String
|
410
499
|
else
|
411
500
|
raise MergeError, "Unsupported types of all of the values. Existing value: " \
|
412
|
-
|
501
|
+
"'#{old_value}', removed change: '#{removed_change}', added change: " \
|
502
|
+
"'#{added_change}'"
|
413
503
|
end
|
414
504
|
end
|
415
505
|
|
416
|
-
def new_simple_attribute_value(type, old_value, removed_change, added_change)
|
506
|
+
def new_simple_attribute_value(type, old_value, removed_change, added_change, attribute_name)
|
417
507
|
if type == Hash
|
418
|
-
new_hash_simple_attribute_value(old_value, removed_change, added_change)
|
508
|
+
new_hash_simple_attribute_value(old_value, removed_change, added_change, attribute_name)
|
419
509
|
elsif type == Array
|
420
|
-
new_array_simple_attribute_value(old_value, removed_change, added_change)
|
510
|
+
new_array_simple_attribute_value(old_value, removed_change, added_change, attribute_name)
|
421
511
|
elsif type == String
|
422
|
-
new_string_simple_attribute_value(old_value, removed_change, added_change)
|
512
|
+
new_string_simple_attribute_value(old_value, removed_change, added_change, attribute_name)
|
423
513
|
else
|
424
514
|
raise MergeError, "Unsupported types of all of the values. Existing value: " \
|
425
|
-
|
515
|
+
"'#{old_value}', removed change: '#{removed_change}', added change: " \
|
516
|
+
"'#{added_change}'"
|
426
517
|
end
|
427
518
|
end
|
428
519
|
|
429
|
-
def new_hash_simple_attribute_value(old_value, removed_change, added_change)
|
520
|
+
def new_hash_simple_attribute_value(old_value, removed_change, added_change, attribute_name)
|
430
521
|
return added_change if ((old_value || {}).to_a - (removed_change || {}).to_a).empty?
|
431
522
|
|
432
523
|
# First apply the added change to see if there are any conflicts with it.
|
433
524
|
new_value = (old_value || {}).merge(added_change || {})
|
525
|
+
conflicting_added_hash_values = (old_value.to_a - new_value.to_a)
|
434
526
|
|
435
|
-
unless
|
436
|
-
|
437
|
-
|
527
|
+
unless conflicting_added_hash_values.empty?
|
528
|
+
override_values = ConflictResolver.override_values_when_keys_already_exist_in_hash?(
|
529
|
+
attribute_name, old_value, added_change
|
530
|
+
)
|
531
|
+
new_value = override_values ? old_value.merge(added_change) : added_change.merge(old_value)
|
438
532
|
end
|
439
533
|
|
440
534
|
if removed_change.nil?
|
441
535
|
return new_value
|
442
536
|
end
|
443
537
|
|
538
|
+
conflicting_removal_hash_values = new_value.select do |key, value|
|
539
|
+
value != removed_change[key] && value != (added_change || {})[key]
|
540
|
+
end
|
541
|
+
|
542
|
+
unless conflicting_removal_hash_values.empty?
|
543
|
+
expected_values =
|
544
|
+
removed_change.select { |key, value| conflicting_removal_hash_values.key?(key) }
|
545
|
+
should_remove_conflicting_values =
|
546
|
+
ConflictResolver.remove_entries_when_unexpected_values_in_hash?(
|
547
|
+
attribute_name, expected_values, conflicting_removal_hash_values
|
548
|
+
)
|
549
|
+
end
|
550
|
+
|
444
551
|
new_value
|
445
552
|
.reject do |key, value|
|
446
|
-
if
|
447
|
-
|
448
|
-
"'#{key}' but it changed to #{value}. This is considered a conflict that should be " \
|
449
|
-
"resolved manually."
|
553
|
+
if conflicting_removal_hash_values.key?(key)
|
554
|
+
next should_remove_conflicting_values
|
450
555
|
end
|
451
556
|
|
452
557
|
removed_change.key?(key)
|
453
558
|
end
|
454
559
|
end
|
455
560
|
|
456
|
-
def new_array_simple_attribute_value(old_value, removed_change, added_change)
|
561
|
+
def new_array_simple_attribute_value(old_value, removed_change, added_change, attribute_name)
|
457
562
|
if old_value.is_a?(String)
|
458
563
|
old_value = [old_value]
|
459
564
|
end
|
@@ -476,10 +581,12 @@ module Kintsugi
|
|
476
581
|
new_value + filtered_added_change
|
477
582
|
end
|
478
583
|
|
479
|
-
def new_string_simple_attribute_value(old_value, removed_change, added_change)
|
584
|
+
def new_string_simple_attribute_value(old_value, removed_change, added_change, attribute_name)
|
480
585
|
if old_value != removed_change && !old_value.nil? && added_change != old_value
|
481
|
-
|
482
|
-
|
586
|
+
use_added_change = ConflictResolver.set_value_to_string_when_unxpected_value?(
|
587
|
+
attribute_name, added_change, removed_change, old_value
|
588
|
+
)
|
589
|
+
return use_added_change ? added_change : old_value
|
483
590
|
end
|
484
591
|
|
485
592
|
added_change
|
@@ -488,26 +595,25 @@ module Kintsugi
|
|
488
595
|
def remove_component(component, change)
|
489
596
|
return if component.nil?
|
490
597
|
|
491
|
-
if component.to_tree_hash != change
|
492
|
-
|
493
|
-
|
494
|
-
"'#{component.display_name}'. Existing component: #{component.to_tree_hash}. " \
|
495
|
-
"Change: #{change}"
|
598
|
+
if component.to_tree_hash != change &&
|
599
|
+
!ConflictResolver.remove_component_when_unexpected_hash?(component, change)
|
600
|
+
return
|
496
601
|
end
|
497
602
|
|
498
|
-
if change["isa"] == "PBXFileReference"
|
499
|
-
|
603
|
+
if change["isa"] == "PBXFileReference" || change["isa"] == "PBXReferenceProxy" ||
|
604
|
+
change["isa"] == "PBXGroup" || change["isa"] == "PBXVariantGroup"
|
605
|
+
remove_build_files_of_file_reference(component)
|
500
606
|
end
|
501
607
|
|
502
608
|
component.remove_from_project
|
503
609
|
end
|
504
610
|
|
505
|
-
def remove_build_files_of_file_reference(file_reference
|
611
|
+
def remove_build_files_of_file_reference(file_reference)
|
506
612
|
# Since the build file's display name depends on the file reference, removing the file
|
507
613
|
# reference before removing it will change the build file's display name which will not be
|
508
614
|
# detected when trying to remove the build file. Therefore, the build files that depend on
|
509
615
|
# the file reference are removed prior to removing the file reference.
|
510
|
-
file_reference.
|
616
|
+
file_reference.referrers.grep(Xcodeproj::Project::PBXBuildFile).each do |build_file|
|
511
617
|
build_file.referrers.each do |referrer|
|
512
618
|
referrer.remove_build_file(build_file)
|
513
619
|
end
|
@@ -565,7 +671,7 @@ module Kintsugi
|
|
565
671
|
add_remote_swift_package_reference(component, change, change_path)
|
566
672
|
else
|
567
673
|
raise MergeError, "Trying to add unsupported component type #{change["isa"]}. Full " \
|
568
|
-
|
674
|
+
"component change is: #{change}"
|
569
675
|
end
|
570
676
|
end
|
571
677
|
|
@@ -581,7 +687,7 @@ module Kintsugi
|
|
581
687
|
containing_component.package_references << remote_swift_package_reference
|
582
688
|
else
|
583
689
|
raise MergeError, "Trying to add remote swift package reference to an unsupported " \
|
584
|
-
|
690
|
+
"component type #{containing_component.isa}. Change is: #{change}"
|
585
691
|
end
|
586
692
|
end
|
587
693
|
|
@@ -597,7 +703,7 @@ module Kintsugi
|
|
597
703
|
containing_component.package_product_dependencies << swift_package_product_dependency
|
598
704
|
else
|
599
705
|
raise MergeError, "Trying to add swift package product dependency to an unsupported " \
|
600
|
-
|
706
|
+
"component type #{containing_component.isa}. Change is: #{change}"
|
601
707
|
end
|
602
708
|
end
|
603
709
|
|
@@ -614,10 +720,10 @@ module Kintsugi
|
|
614
720
|
end.nil?
|
615
721
|
end
|
616
722
|
file_reference =
|
617
|
-
find_reference_proxy(containing_component.project, change
|
723
|
+
find_reference_proxy(containing_component.project, change,
|
618
724
|
reference_filter: filter_references_without_build_files)
|
619
725
|
if file_reference.nil?
|
620
|
-
file_reference = find_reference_proxy(containing_component.project, change
|
726
|
+
file_reference = find_reference_proxy(containing_component.project, change)
|
621
727
|
end
|
622
728
|
containing_component.file_ref = file_reference
|
623
729
|
when Xcodeproj::Project::PBXGroup
|
@@ -630,7 +736,7 @@ module Kintsugi
|
|
630
736
|
add_attributes_to_component(reference_proxy, change, change_path)
|
631
737
|
else
|
632
738
|
raise MergeError, "Trying to add reference proxy to an unsupported component type " \
|
633
|
-
|
739
|
+
"#{containing_component.isa}. Change is: #{change}"
|
634
740
|
end
|
635
741
|
end
|
636
742
|
|
@@ -639,15 +745,11 @@ module Kintsugi
|
|
639
745
|
when Xcodeproj::Project::PBXBuildFile
|
640
746
|
containing_component.file_ref =
|
641
747
|
find_variant_group(containing_component.project, change["displayName"])
|
642
|
-
when Xcodeproj::Project::PBXGroup
|
643
|
-
|
644
|
-
change).nil?
|
645
|
-
raise "Group should have been added already, so this is most likely a bug in Kintsugi" \
|
646
|
-
"Change is: #{change}. Change path: #{change_path}"
|
647
|
-
end
|
748
|
+
when Xcodeproj::Project::PBXGroup
|
749
|
+
# Adding variant groups to groups is handled by another part of the code.
|
648
750
|
else
|
649
751
|
raise MergeError, "Trying to add variant group to an unsupported component type " \
|
650
|
-
|
752
|
+
"#{containing_component.isa}. Change is: #{change}"
|
651
753
|
end
|
652
754
|
end
|
653
755
|
|
@@ -699,7 +801,7 @@ module Kintsugi
|
|
699
801
|
def add_build_file(build_phase, change, change_path)
|
700
802
|
if change["fileRef"].nil?
|
701
803
|
puts "Warning: Trying to add a build file without any file reference to build phase " \
|
702
|
-
|
804
|
+
"'#{build_phase}'"
|
703
805
|
return
|
704
806
|
end
|
705
807
|
|
@@ -748,7 +850,7 @@ module Kintsugi
|
|
748
850
|
component.remote_ref = container_proxy
|
749
851
|
else
|
750
852
|
raise MergeError, "Trying to add container item proxy to an unsupported component type " \
|
751
|
-
|
853
|
+
"#{containing_component.isa}. Change is: #{change}"
|
752
854
|
end
|
753
855
|
add_attributes_to_component(container_proxy, change, change_path,
|
754
856
|
ignore_keys: ["containerPortal"])
|
@@ -772,10 +874,10 @@ module Kintsugi
|
|
772
874
|
|
773
875
|
if container_item_proxies.length > 1
|
774
876
|
puts "Debug: Found more than one potential dependency with name " \
|
775
|
-
|
877
|
+
"'#{container_item_proxy_change["remoteInfo"]}'. Using the first one."
|
776
878
|
elsif container_item_proxies.empty?
|
777
879
|
puts "Warning: No container portal was found for dependency with name " \
|
778
|
-
|
880
|
+
"'#{container_item_proxy_change["remoteInfo"]}'."
|
779
881
|
return
|
780
882
|
end
|
781
883
|
|
@@ -800,8 +902,8 @@ module Kintsugi
|
|
800
902
|
|
801
903
|
unless subproject_reference
|
802
904
|
raise MergeError, "No file reference was found for project reference with change " \
|
803
|
-
|
804
|
-
|
905
|
+
"#{project_reference_change}. This might mean that the file used to " \
|
906
|
+
"exist in the project the but was removed at some point"
|
805
907
|
end
|
806
908
|
|
807
909
|
attribute =
|
@@ -841,8 +943,6 @@ module Kintsugi
|
|
841
943
|
def add_file_reference(containing_component, change, change_path)
|
842
944
|
# base configuration reference and product reference always reference a file that exists
|
843
945
|
# inside a group, therefore in these cases the file is searched for.
|
844
|
-
# In the case of group and variant group, the file can't exist in another group, therefore a
|
845
|
-
# new file reference is always created.
|
846
946
|
case containing_component
|
847
947
|
when Xcodeproj::Project::XCBuildConfiguration
|
848
948
|
containing_component.base_configuration_reference =
|
@@ -852,15 +952,11 @@ module Kintsugi
|
|
852
952
|
find_file(containing_component.project, change["path"])
|
853
953
|
when Xcodeproj::Project::PBXBuildFile
|
854
954
|
containing_component.file_ref = find_file(containing_component.project, change["path"])
|
855
|
-
when Xcodeproj::Project::PBXGroup
|
856
|
-
|
857
|
-
change["path"]).nil?
|
858
|
-
raise "File should have been added already, so this is most likely a bug in Kintsugi" \
|
859
|
-
"Change is: #{change}. Change path: #{change_path}"
|
860
|
-
end
|
955
|
+
when Xcodeproj::Project::PBXGroup
|
956
|
+
# Adding files to groups is handled by another part of the code.
|
861
957
|
else
|
862
958
|
raise MergeError, "Trying to add file reference to an unsupported component type " \
|
863
|
-
|
959
|
+
"#{containing_component.isa}. Change is: #{change}"
|
864
960
|
end
|
865
961
|
end
|
866
962
|
|
@@ -871,11 +967,6 @@ module Kintsugi
|
|
871
967
|
.find { |file| file.path == filepath }
|
872
968
|
end
|
873
969
|
|
874
|
-
def adding_files_and_groups_allowed?(change_path)
|
875
|
-
change_path.start_with?("rootObject/mainGroup") ||
|
876
|
-
change_path.start_with?("rootObject/projectReferences")
|
877
|
-
end
|
878
|
-
|
879
970
|
def add_group(containing_component, change, change_path)
|
880
971
|
case containing_component
|
881
972
|
when Xcodeproj::Project::ObjectDictionary
|
@@ -884,13 +975,11 @@ module Kintsugi
|
|
884
975
|
containing_component[:product_group] = new_group
|
885
976
|
add_attributes_to_component(new_group, change, change_path)
|
886
977
|
when Xcodeproj::Project::PBXGroup
|
887
|
-
|
888
|
-
raise "Group should have been added already, so this is most likely a bug in Kintsugi" \
|
889
|
-
"Change is: #{change}. Change path: #{change_path}"
|
890
|
-
end
|
978
|
+
# Adding groups to groups is handled by another part of the code.
|
891
979
|
else
|
892
980
|
raise MergeError, "Trying to add group to an unsupported component type " \
|
893
|
-
|
981
|
+
"#{containing_component.isa}. Change is: #{change}. Change path: " \
|
982
|
+
"#{change_path}"
|
894
983
|
end
|
895
984
|
end
|
896
985
|
|
@@ -917,7 +1006,7 @@ module Kintsugi
|
|
917
1006
|
end
|
918
1007
|
else
|
919
1008
|
raise MergeError, "Trying to add attribute of unsupported type '#{change_value.class}' " \
|
920
|
-
|
1009
|
+
"to object #{component}. Attribute name is '#{change_name}'"
|
921
1010
|
end
|
922
1011
|
end
|
923
1012
|
end
|
@@ -935,44 +1024,37 @@ module Kintsugi
|
|
935
1024
|
if file_references.length > 1
|
936
1025
|
puts "Debug: Found more than one matching file with path '#{path}'. Using the first one."
|
937
1026
|
elsif file_references.empty?
|
938
|
-
puts "Debug: No file reference found for file with path '#{path}'."
|
939
1027
|
return
|
940
1028
|
end
|
941
1029
|
|
942
1030
|
file_references.first
|
943
1031
|
end
|
944
1032
|
|
945
|
-
def find_reference_proxy(project,
|
1033
|
+
def find_reference_proxy(project, change, reference_filter: ->(_) { true })
|
946
1034
|
reference_proxies = project.root_object.project_references.map do |project_ref_and_products|
|
947
|
-
|
948
|
-
|
949
|
-
|
1035
|
+
project_ref_and_products[:product_group].children.find do |reference_proxy|
|
1036
|
+
reference_proxy.display_name == change["displayName"] &&
|
1037
|
+
reference_filter.call(reference_proxy)
|
1038
|
+
end
|
950
1039
|
end.compact
|
951
1040
|
|
952
1041
|
if reference_proxies.length > 1
|
953
1042
|
puts "Debug: Found more than one matching reference proxy with name " \
|
954
|
-
|
1043
|
+
"'#{change["remoteInfo"]}'. Using the first one."
|
955
1044
|
elsif reference_proxies.empty?
|
956
|
-
puts "Warning: No reference proxy was found for name "
|
957
|
-
"'#{container_item_proxy_change["remoteInfo"]}'."
|
1045
|
+
puts "Warning: No reference proxy was found for name '#{change["remoteInfo"]}'."
|
958
1046
|
return
|
959
1047
|
end
|
960
1048
|
|
961
1049
|
reference_proxies.first
|
962
1050
|
end
|
963
1051
|
|
964
|
-
def find_reference_proxy_in_component(component, container_item_proxy_change,
|
965
|
-
reference_filter: ->(_) { true })
|
966
|
-
component.find do |product|
|
967
|
-
product.remote_ref.remote_global_id_string ==
|
968
|
-
container_item_proxy_change["remoteGlobalIDString"] &&
|
969
|
-
product.remote_ref.remote_info == container_item_proxy_change["remoteInfo"] &&
|
970
|
-
reference_filter.call(product)
|
971
|
-
end
|
972
|
-
end
|
973
|
-
|
974
1052
|
def join_path(left, right)
|
975
1053
|
left.empty? ? right : "#{left}/#{right}"
|
976
1054
|
end
|
1055
|
+
|
1056
|
+
def parent_group_path(group_path)
|
1057
|
+
group_path[/(.*)\//, 1] || ""
|
1058
|
+
end
|
977
1059
|
end
|
978
1060
|
end
|