From 4c26a59e17b5a3ad19d5e383b76eb4ba3174a1ff Mon Sep 17 00:00:00 2001 From: Eshed Shaham Date: Tue, 7 May 2024 13:37:21 +0200 Subject: [PATCH] apply_change_to_project: use attribute_name for building change_path. When merging the tree, Kintsugi keeps track of where it is, to allow finding the corresponding component in the source project. Until this commit, the path was constructed in `add_child_to_component` by appending the display name of the added component. When adding a file reference this path was used to traverse the project tree along each object's attributes. This caused a bug when the display name and the attribute name are different, e.g., a target's build configuration list has a display name of "ConfigurationList" and an attribute name of "build_configuration_list". The camel-case was converted correctly, but the merge failed due to not finding the attribute "configuration_list". The solution to this issue is to use the attribute names to create the path, except when adding an object to a list, where there is no attribute and then the display name is used. --- lib/kintsugi/apply_change_to_project.rb | 17 ++++++------- spec/kintsugi_apply_change_to_project_spec.rb | 25 ++++++++++++++++++- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/lib/kintsugi/apply_change_to_project.rb b/lib/kintsugi/apply_change_to_project.rb index 44de10d..46905d6 100644 --- a/lib/kintsugi/apply_change_to_project.rb +++ b/lib/kintsugi/apply_change_to_project.rb @@ -306,7 +306,8 @@ def apply_change_to_component(parent_component, change_name, change, parent_chan component = child_component(parent_component, change_name) elsif change[:added].is_a?(Array) (change[:added]).each do |added_change| - add_child_to_component(parent_component, added_change, change_path) + add_child_to_component(parent_component, added_change, + join_path(change_path, added_change["displayName"])) end elsif !change[:added].nil? raise MergeError, "Unsupported added change type for #{change[:added]}" @@ -341,9 +342,8 @@ def resolve_nonexistent_component(parent_component, change_path) else parent_component end - parent_change_path = change_path.split("/")[0...-1].join("/") add_child_to_component(non_object_list_parent, source_project_component.to_tree_hash, - parent_change_path) + change_path) component_at_path(non_object_list_parent.project, change_path) end @@ -637,9 +637,7 @@ def remove_build_files_of_file_reference(file_reference) end end - def add_child_to_component(component, change, component_change_path) - change_path = join_path(component_change_path, change["displayName"]) - + def add_child_to_component(component, change, change_path) if change["ProjectRef"] && change["ProductGroup"] add_subproject_reference(component, change, change_path) return @@ -1031,13 +1029,14 @@ def add_attributes_to_component(component, change, change_path, ignore_keys: []) next end + child_path = join_path(change_path, change_name) case change_value when Hash - add_child_to_component(component, change_value, change_path) + add_child_to_component(component, change_value, child_path) when Array change_value.each do |added_attribute_element| - add_child_to_component(component, added_attribute_element, - "#{change_path}/#{change_name}") + element_path = join_path(child_path, added_attribute_element["displayName"]) + add_child_to_component(component, added_attribute_element, element_path) end else raise MergeError, "Trying to add attribute of unsupported type '#{change_value.class}' " \ diff --git a/spec/kintsugi_apply_change_to_project_spec.rb b/spec/kintsugi_apply_change_to_project_spec.rb index d364754..7ef6943 100644 --- a/spec/kintsugi_apply_change_to_project_spec.rb +++ b/spec/kintsugi_apply_change_to_project_spec.rb @@ -1399,8 +1399,9 @@ expect(base_project).to be_equivalent_to_project(theirs_project) end - it "adds base configuration reference to new target" do + it "adds base configuration reference" do base_project.main_group.new_reference("baz") + base_project.save theirs_project = create_copy_of_project(base_project.path, "theirs") configuration_reference = theirs_project.main_group.find_subpath("baz") @@ -1414,6 +1415,28 @@ expect(base_project).to be_equivalent_to_project(theirs_project) end + + it "adds base configuration reference to new configuration in a new list" do + base_project.main_group.new_reference("baz") + base_project.targets[0].build_configuration_list = nil + base_project.save + + theirs_project = create_copy_of_project(base_project.path, "theirs") + configuration_reference = theirs_project.main_group.find_subpath("baz") + + configuration_list = theirs_project.new(Xcodeproj::Project::XCConfigurationList) + theirs_project.targets[0].build_configuration_list = configuration_list + + build_configuration = theirs_project.new(Xcodeproj::Project::XCBuildConfiguration) + build_configuration.base_configuration_reference = configuration_reference + configuration_list.build_configurations << build_configuration + + changes_to_apply = get_diff(theirs_project, base_project) + + described_class.apply_change_to_project(base_project, changes_to_apply, theirs_project) + + expect(base_project).to be_equivalent_to_project(theirs_project) + end end it "adds known regions" do