kintsugi 0.7.0 → 0.7.2
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/kintsugi/apply_change_to_project.rb +54 -32
- data/lib/kintsugi/cli.rb +76 -63
- data/lib/kintsugi/version.rb +1 -1
- data/lib/kintsugi/xcodeproj_extensions.rb +12 -0
- data/spec/kintsugi_apply_change_to_project_spec.rb +21 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c3024a2418328a3a3fb120f6b2bb7250477079f922dbd1882785ed065b3ff8a8
|
4
|
+
data.tar.gz: 98e1e7752eee2e47555b8eb0d21189b06869f284426279ff5aed403c7daa1e7f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c3a847fa528aaddb9c537c6f6a7aa91434ddf4d817f8434173d162617a854a3f0f9c012c7c2699c20e6901617f6c2eb91eb429c72a2181163e72a25898dc7ce8
|
7
|
+
data.tar.gz: ef5f8ae4c8da4c79aac9510892b714c0801b58829af83a84146add68404be0106c09cd71f219d6a6b1e832d2c05e596a5bd44428388ef91d35e33ff897ef4fa7
|
@@ -281,7 +281,8 @@ module Kintsugi
|
|
281
281
|
end
|
282
282
|
|
283
283
|
if change["isa"]
|
284
|
-
component = replace_component_with_new_type(parent_component, attribute_name, change
|
284
|
+
component = replace_component_with_new_type(parent_component, attribute_name, change,
|
285
|
+
change_path)
|
285
286
|
change = change_for_component_of_new_type(component, change)
|
286
287
|
else
|
287
288
|
component = child_component(parent_component, change_name)
|
@@ -340,8 +341,9 @@ module Kintsugi
|
|
340
341
|
else
|
341
342
|
parent_component
|
342
343
|
end
|
344
|
+
parent_change_path = change_path.split("/")[0...-1].join("/")
|
343
345
|
add_child_to_component(non_object_list_parent, source_project_component.to_tree_hash,
|
344
|
-
|
346
|
+
parent_change_path)
|
345
347
|
component_at_path(non_object_list_parent.project, change_path)
|
346
348
|
end
|
347
349
|
|
@@ -381,9 +383,10 @@ module Kintsugi
|
|
381
383
|
end
|
382
384
|
end
|
383
385
|
|
384
|
-
def replace_component_with_new_type(parent_component, name_in_parent_component, change
|
386
|
+
def replace_component_with_new_type(parent_component, name_in_parent_component, change,
|
387
|
+
change_path)
|
385
388
|
old_component = parent_component.send(name_in_parent_component)
|
386
|
-
new_component = component_of_new_type(parent_component, change, old_component)
|
389
|
+
new_component = component_of_new_type(parent_component, change, old_component, change_path)
|
387
390
|
|
388
391
|
copy_attributes_to_new_component(old_component, new_component)
|
389
392
|
|
@@ -391,18 +394,32 @@ module Kintsugi
|
|
391
394
|
new_component
|
392
395
|
end
|
393
396
|
|
394
|
-
def component_of_new_type(parent_component, change, old_component)
|
397
|
+
def component_of_new_type(parent_component, change, old_component, change_path)
|
395
398
|
if change["isa"][:added] == "PBXFileReference"
|
396
|
-
|
399
|
+
source_project_component =
|
400
|
+
component_at_path(@change_source_project, change_path.split("/")[0...-1].join("/"))
|
401
|
+
if source_project_component.nil?
|
402
|
+
raise MergeError, "Couldn't find file reference in the project where the file should " \
|
403
|
+
"reside. The file's change is #{change}. Change path is #{change_path}"
|
404
|
+
end
|
405
|
+
|
397
406
|
case parent_component
|
398
407
|
when Xcodeproj::Project::XCBuildConfiguration
|
399
|
-
parent_component.base_configuration_reference =
|
408
|
+
parent_component.base_configuration_reference =
|
409
|
+
parent_component.project.group_or_file_at_path(
|
410
|
+
source_project_component.base_configuration_reference.hierarchy_path
|
411
|
+
.delete_prefix("/")
|
412
|
+
)
|
400
413
|
return parent_component.base_configuration_reference
|
401
414
|
when Xcodeproj::Project::PBXNativeTarget
|
402
|
-
parent_component.product_reference =
|
415
|
+
parent_component.product_reference = parent_component.project.group_or_file_at_path(
|
416
|
+
source_project_component.product_reference.hierarchy_path.delete_prefix("/")
|
417
|
+
)
|
403
418
|
return parent_component.product_reference
|
404
419
|
when Xcodeproj::Project::PBXBuildFile
|
405
|
-
parent_component.file_ref =
|
420
|
+
parent_component.file_ref = parent_component.project.group_or_file_at_path(
|
421
|
+
source_project_component.file_ref.hierarchy_path.delete_prefix("/")
|
422
|
+
)
|
406
423
|
return parent_component.file_ref
|
407
424
|
end
|
408
425
|
end
|
@@ -891,14 +908,19 @@ module Kintsugi
|
|
891
908
|
end
|
892
909
|
return if !Settings.allow_duplicates && !existing_subproject.nil?
|
893
910
|
|
894
|
-
|
911
|
+
source_project_subproject_reference = component_at_path(@change_source_project, change_path)
|
912
|
+
if source_project_subproject_reference.nil?
|
913
|
+
raise MergeError, "Project reference with change #{project_reference_change} doesn't " \
|
914
|
+
"exist in the source project. Change path is #{change_path}"
|
915
|
+
end
|
916
|
+
|
917
|
+
subproject_reference = root_object.project.files.find do |file_reference|
|
918
|
+
file_reference.hierarchy_path ==
|
919
|
+
source_project_subproject_reference.project_ref.hierarchy_path &&
|
895
920
|
root_object.project_references.find do |project_reference|
|
896
921
|
project_reference.project_ref.uuid == file_reference.uuid
|
897
922
|
end.nil?
|
898
923
|
end
|
899
|
-
subproject_reference =
|
900
|
-
find_file(root_object.project, project_reference_change["ProjectRef"]["path"],
|
901
|
-
file_filter: filter_subproject_without_project_references)
|
902
924
|
|
903
925
|
unless subproject_reference
|
904
926
|
raise MergeError, "No file reference was found for project reference with change " \
|
@@ -941,17 +963,29 @@ module Kintsugi
|
|
941
963
|
end
|
942
964
|
|
943
965
|
def add_file_reference(containing_component, change, change_path)
|
944
|
-
|
945
|
-
|
966
|
+
source_project_component =
|
967
|
+
component_at_path(@change_source_project, change_path.split("/")[0...-1].join("/"))
|
968
|
+
if source_project_component.nil?
|
969
|
+
raise MergeError, "Couldn't find file reference in the project where the file should " \
|
970
|
+
"reside. The file's change is #{change}. Change path is #{change_path}"
|
971
|
+
end
|
972
|
+
|
946
973
|
case containing_component
|
947
974
|
when Xcodeproj::Project::XCBuildConfiguration
|
948
975
|
containing_component.base_configuration_reference =
|
949
|
-
|
976
|
+
containing_component.project.group_or_file_at_path(
|
977
|
+
source_project_component.base_configuration_reference.hierarchy_path.delete_prefix("/")
|
978
|
+
)
|
950
979
|
when Xcodeproj::Project::PBXNativeTarget
|
951
980
|
containing_component.product_reference =
|
952
|
-
|
981
|
+
containing_component.project.group_or_file_at_path(
|
982
|
+
source_project_component.product_reference.hierarchy_path.delete_prefix("/")
|
983
|
+
)
|
953
984
|
when Xcodeproj::Project::PBXBuildFile
|
954
|
-
containing_component.file_ref =
|
985
|
+
containing_component.file_ref =
|
986
|
+
containing_component.project.group_or_file_at_path(
|
987
|
+
source_project_component.file_ref.hierarchy_path.delete_prefix("/")
|
988
|
+
)
|
955
989
|
when Xcodeproj::Project::PBXGroup
|
956
990
|
# Adding files to groups is handled by another part of the code.
|
957
991
|
else
|
@@ -1002,7 +1036,8 @@ module Kintsugi
|
|
1002
1036
|
add_child_to_component(component, change_value, change_path)
|
1003
1037
|
when Array
|
1004
1038
|
change_value.each do |added_attribute_element|
|
1005
|
-
add_child_to_component(component, added_attribute_element,
|
1039
|
+
add_child_to_component(component, added_attribute_element,
|
1040
|
+
"#{change_path}/#{change_name}")
|
1006
1041
|
end
|
1007
1042
|
else
|
1008
1043
|
raise MergeError, "Trying to add attribute of unsupported type '#{change_value.class}' " \
|
@@ -1017,19 +1052,6 @@ module Kintsugi
|
|
1017
1052
|
end.default_value
|
1018
1053
|
end
|
1019
1054
|
|
1020
|
-
def find_file(project, path, file_filter: ->(_) { true })
|
1021
|
-
file_references = project.files.select do |file_reference|
|
1022
|
-
file_reference.path == path && file_filter.call(file_reference)
|
1023
|
-
end
|
1024
|
-
if file_references.length > 1
|
1025
|
-
puts "Debug: Found more than one matching file with path '#{path}'. Using the first one."
|
1026
|
-
elsif file_references.empty?
|
1027
|
-
return
|
1028
|
-
end
|
1029
|
-
|
1030
|
-
file_references.first
|
1031
|
-
end
|
1032
|
-
|
1033
1055
|
def find_reference_proxy(project, change, reference_filter: ->(_) { true })
|
1034
1056
|
reference_proxies = project.root_object.project_references.map do |project_ref_and_products|
|
1035
1057
|
project_ref_and_products[:product_group].children.find do |reference_proxy|
|
data/lib/kintsugi/cli.rb
CHANGED
@@ -31,21 +31,12 @@ module Kintsugi
|
|
31
31
|
Command = Struct.new(:option_parser, :action, :description, keyword_init: true)
|
32
32
|
|
33
33
|
def create_driver_subcommand
|
34
|
-
option_parser =
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
opts.on("--interactive-resolution=FLAG", TrueClass, "In case a conflict that requires " \
|
42
|
-
"human decision to resolve, show an interactive prompt with choices to resolve it")
|
43
|
-
|
44
|
-
opts.on("-h", "--help", "Prints this help") do
|
45
|
-
puts opts
|
46
|
-
exit
|
47
|
-
end
|
48
|
-
end
|
34
|
+
option_parser = create_base_option_parser
|
35
|
+
option_parser.banner = "Usage: kintsugi driver BASE OURS THEIRS ORIGINAL_FILE_PATH " \
|
36
|
+
"[options]\n" \
|
37
|
+
"Uses Kintsugi as a Git merge driver. Parameters " \
|
38
|
+
"should be the path to base version of the file, path to ours version, path to " \
|
39
|
+
"theirs version, and the original file path."
|
49
40
|
|
50
41
|
driver_action = lambda { |options, arguments|
|
51
42
|
if arguments.count != 4
|
@@ -54,9 +45,7 @@ module Kintsugi
|
|
54
45
|
exit(1)
|
55
46
|
end
|
56
47
|
|
57
|
-
|
58
|
-
Settings.interactive_resolution = options[:"interactive-resolution"]
|
59
|
-
end
|
48
|
+
update_settings(options)
|
60
49
|
|
61
50
|
Kintsugi.three_way_merge(arguments[0], arguments[1], arguments[2], arguments[3])
|
62
51
|
warn "\e[32mKintsugi auto-merged #{arguments[3]}\e[0m"
|
@@ -70,17 +59,10 @@ module Kintsugi
|
|
70
59
|
end
|
71
60
|
|
72
61
|
def create_install_driver_subcommand
|
73
|
-
option_parser =
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
"to `kintsugi driver`."
|
78
|
-
|
79
|
-
opts.on("-h", "--help", "Prints this help") do
|
80
|
-
puts opts
|
81
|
-
exit
|
82
|
-
end
|
83
|
-
end
|
62
|
+
option_parser = create_base_option_parser
|
63
|
+
option_parser.banner = "Usage: kintsugi install-driver [driver-options]\n" \
|
64
|
+
"Installs Kintsugi as a Git merge driver globally. `driver-options` will be passed " \
|
65
|
+
"to `kintsugi driver`."
|
84
66
|
|
85
67
|
action = lambda { |options, arguments|
|
86
68
|
if arguments.count != 0
|
@@ -94,7 +76,9 @@ module Kintsugi
|
|
94
76
|
exit(1)
|
95
77
|
end
|
96
78
|
|
97
|
-
|
79
|
+
driver_options = extract_driver_options(options, option_parser)
|
80
|
+
|
81
|
+
install_kintsugi_driver_globally(driver_options)
|
98
82
|
puts "Done! 🪄"
|
99
83
|
}
|
100
84
|
|
@@ -105,9 +89,30 @@ module Kintsugi
|
|
105
89
|
)
|
106
90
|
end
|
107
91
|
|
92
|
+
def extract_driver_options(options, option_parser)
|
93
|
+
options.map do |option_name, option_value|
|
94
|
+
switch = option_parser.top.search(:long, option_name.to_s)
|
95
|
+
prefix = "--"
|
96
|
+
if switch.nil?
|
97
|
+
switch = option_parser.top.search(:short, option_name.to_s)
|
98
|
+
prefix = "-"
|
99
|
+
end
|
100
|
+
case switch
|
101
|
+
when OptionParser::Switch::NoArgument
|
102
|
+
[prefix + option_name.to_s]
|
103
|
+
when NilClass
|
104
|
+
puts "Invalid flag #{option_name} passed to 'install-driver' subcommand\n\n"
|
105
|
+
puts option_parser
|
106
|
+
exit(1)
|
107
|
+
else
|
108
|
+
[prefix + option_name.to_s, option_value]
|
109
|
+
end
|
110
|
+
end.flatten
|
111
|
+
end
|
112
|
+
|
108
113
|
def install_kintsugi_driver_globally(options)
|
109
114
|
`git config --global merge.kintsugi.name "Kintsugi driver"`
|
110
|
-
kintsugi_command = "kintsugi driver %O %A %B %P #{options}"
|
115
|
+
kintsugi_command = "kintsugi driver %O %A %B %P #{options.join(" ")}".rstrip
|
111
116
|
`git config --global merge.kintsugi.driver "#{kintsugi_command}"`
|
112
117
|
|
113
118
|
attributes_file_path = global_attributes_file_path
|
@@ -173,33 +178,21 @@ module Kintsugi
|
|
173
178
|
end
|
174
179
|
|
175
180
|
def create_root_command
|
176
|
-
option_parser =
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
opts.on("-h", "--help", "Prints this help") do
|
187
|
-
puts opts
|
188
|
-
exit
|
189
|
-
end
|
190
|
-
|
191
|
-
opts.on("-v", "--version", "Prints version") do
|
192
|
-
puts Version::STRING
|
193
|
-
exit
|
194
|
-
end
|
195
|
-
|
196
|
-
opts.on("--allow-duplicates", "Allow to add duplicates of the same entity")
|
181
|
+
option_parser = create_base_option_parser
|
182
|
+
option_parser.banner = "Kintsugi, version #{Version::STRING}\n" \
|
183
|
+
"Copyright (c) 2021 Lightricks\n\n" \
|
184
|
+
"Usage: kintsugi <pbxproj_filepath> [options]\n" \
|
185
|
+
" kintsugi <subcommand> [options]"
|
186
|
+
|
187
|
+
option_parser.on("-v", "--version", "Prints version") do
|
188
|
+
puts Version::STRING
|
189
|
+
exit
|
190
|
+
end
|
197
191
|
|
198
|
-
|
199
|
-
|
192
|
+
option_parser.on("--changes-output-path=PATH", "Path to which changes applied to the " \
|
193
|
+
"project are written in JSON format. Used for debug purposes.")
|
200
194
|
|
201
|
-
|
202
|
-
end
|
195
|
+
option_parser.on_tail("\nSUBCOMMANDS\n#{subcommands_descriptions(subcommands)}")
|
203
196
|
|
204
197
|
root_action = lambda { |options, arguments|
|
205
198
|
if arguments.count != 1
|
@@ -208,13 +201,7 @@ module Kintsugi
|
|
208
201
|
exit(1)
|
209
202
|
end
|
210
203
|
|
211
|
-
|
212
|
-
Settings.allow_duplicates = true
|
213
|
-
end
|
214
|
-
|
215
|
-
unless options[:"interactive-resolution"].nil?
|
216
|
-
Settings.interactive_resolution = options[:"interactive-resolution"]
|
217
|
-
end
|
204
|
+
update_settings(options)
|
218
205
|
|
219
206
|
project_file_path = File.expand_path(arguments[0])
|
220
207
|
Kintsugi.resolve_conflicts(project_file_path, options[:"changes-output-path"])
|
@@ -228,6 +215,32 @@ module Kintsugi
|
|
228
215
|
)
|
229
216
|
end
|
230
217
|
|
218
|
+
def create_base_option_parser
|
219
|
+
OptionParser.new do |opts|
|
220
|
+
opts.separator ""
|
221
|
+
|
222
|
+
opts.on("-h", "--help", "Prints this help") do
|
223
|
+
puts opts
|
224
|
+
exit
|
225
|
+
end
|
226
|
+
|
227
|
+
opts.on("--allow-duplicates", "Allow to add duplicates of the same entity")
|
228
|
+
|
229
|
+
opts.on("--interactive-resolution=FLAG", TrueClass, "In case a conflict that requires " \
|
230
|
+
"human decision to resolve, show an interactive prompt with choices to resolve it")
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
def update_settings(options)
|
235
|
+
if options[:"allow-duplicates"]
|
236
|
+
Settings.allow_duplicates = true
|
237
|
+
end
|
238
|
+
|
239
|
+
unless options[:"interactive-resolution"].nil?
|
240
|
+
Settings.interactive_resolution = options[:"interactive-resolution"]
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
231
244
|
def subcommands_descriptions(subcommands)
|
232
245
|
longest_subcommand_length = subcommands.keys.map(&:length).max + 4
|
233
246
|
format_string = " %-#{longest_subcommand_length}s%s"
|
data/lib/kintsugi/version.rb
CHANGED
@@ -113,6 +113,18 @@ module Xcodeproj
|
|
113
113
|
string.scan(/ *((['"]?).*?[^\\]\2)(?=( |\z))/).map(&:first)
|
114
114
|
end
|
115
115
|
end
|
116
|
+
|
117
|
+
# Modifies `PBXTargetDependency`'s `to_tree_hash` to not crash if `target_proxy` is `nil`.
|
118
|
+
# The same fix was done in https://github.com/CocoaPods/Xcodeproj/pull/915/.
|
119
|
+
class PBXTargetDependency
|
120
|
+
def to_tree_hash
|
121
|
+
hash = {}
|
122
|
+
hash['displayName'] = display_name
|
123
|
+
hash['isa'] = isa
|
124
|
+
hash['targetProxy'] = target_proxy.to_tree_hash if target_proxy
|
125
|
+
hash
|
126
|
+
end
|
127
|
+
end
|
116
128
|
end
|
117
129
|
end
|
118
130
|
|
@@ -585,6 +585,26 @@ describe Kintsugi, :apply_change_to_project do
|
|
585
585
|
expect(base_project).to be_equivalent_to_project(theirs_project)
|
586
586
|
end
|
587
587
|
|
588
|
+
it "keeps different files with the same name in their respective targets" do
|
589
|
+
file_reference = base_project.main_group.new_reference("file1.swift")
|
590
|
+
base_project.targets[0].source_build_phase.add_file_reference(file_reference)
|
591
|
+
|
592
|
+
base_project.new_target("com.apple.product-type.library.static", "bar", :ios)
|
593
|
+
base_project.main_group.find_subpath("new_group", true).new_reference("file1.swift")
|
594
|
+
base_project.save
|
595
|
+
|
596
|
+
theirs_project = create_copy_of_project(base_project.path, "theirs")
|
597
|
+
second_target = theirs_project.targets[1]
|
598
|
+
second_file_reference = theirs_project.main_group.find_subpath("new_group/file1.swift")
|
599
|
+
second_target.source_build_phase.add_file_reference(second_file_reference)
|
600
|
+
|
601
|
+
changes_to_apply = get_diff(theirs_project, base_project)
|
602
|
+
|
603
|
+
described_class.apply_change_to_project(base_project, changes_to_apply, theirs_project)
|
604
|
+
expect(base_project).to be_equivalent_to_project(theirs_project)
|
605
|
+
expect(base_project.main_group.find_subpath("new_group/file1.swift").build_files).not_to be_empty
|
606
|
+
end
|
607
|
+
|
588
608
|
it "moves file that is referenced by a target from a group to the main group" do
|
589
609
|
file_reference = base_project.main_group.find_subpath("new_group", true).new_reference("bar")
|
590
610
|
base_project.targets[0].source_build_phase.add_file_reference(file_reference)
|
@@ -1764,7 +1784,7 @@ describe Kintsugi, :apply_change_to_project do
|
|
1764
1784
|
end
|
1765
1785
|
end
|
1766
1786
|
|
1767
|
-
describe "
|
1787
|
+
describe "resolving conflicts interactively" do
|
1768
1788
|
let(:test_prompt) { TTY::Prompt::Test.new }
|
1769
1789
|
|
1770
1790
|
before do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kintsugi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
4
|
+
version: 0.7.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Yohay
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-08-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: tty-prompt
|
@@ -184,7 +184,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
184
184
|
- !ruby/object:Gem::Version
|
185
185
|
version: '0'
|
186
186
|
requirements: []
|
187
|
-
rubygems_version: 3.4.
|
187
|
+
rubygems_version: 3.4.18
|
188
188
|
signing_key:
|
189
189
|
specification_version: 4
|
190
190
|
summary: pbxproj files git conflicts solver
|