diff --git a/lib/kintsugi/apply_change_to_project.rb b/lib/kintsugi/apply_change_to_project.rb index 403e307..82657c9 100644 --- a/lib/kintsugi/apply_change_to_project.rb +++ b/lib/kintsugi/apply_change_to_project.rb @@ -309,8 +309,21 @@ def add_child_to_component(component, change) def add_reference_proxy(containing_component, change) case containing_component when Xcodeproj::Project::PBXBuildFile - containing_component.file_ref = find_reference_proxy(containing_component.project, - change["remoteRef"]) + # If there are two file references that refer to the same file, one with a build file and + # the other one without, this method will prefer to take the one without the build file. + # This assumes that it's preferred to have a file reference with build file than a file + # reference without/with two build files. + filter_files_without_build_files = lambda do |reference| + reference.referrers.find do |referrer| + referrer.is_a?(Xcodeproj::Project::PBXBuildFile) + end.nil? + end + file_reference = find_reference_proxy(containing_component.project, change["remoteRef"], + reference_filter: filter_files_without_build_files) + if file_reference.nil? + file_reference = find_reference_proxy(containing_component.project, change["remoteRef"]) + end + containing_component.file_ref = file_reference when Xcodeproj::Project::PBXGroup reference_proxy = containing_component.project.new(Xcodeproj::Project::PBXReferenceProxy) containing_component << reference_proxy @@ -469,7 +482,7 @@ def add_subproject_reference(root_object, project_reference_change) end subproject_reference = find_file(root_object.project, project_reference_change["ProjectRef"], - filter_file: filter_subproject_without_project_references) + file_filter: filter_subproject_without_project_references) attribute = Xcodeproj::Project::PBXProject.references_by_keys_attributes @@ -572,10 +585,9 @@ def add_attributes_to_component(component, change, ignore_keys: []) end end - def find_file(project, file_reference_change, filter_file: ->(_) { true }) + def find_file(project, file_reference_change, file_filter: ->(_) { true }) file_references = project.files.select do |file_reference| - next file_reference.path == file_reference_change["path"] && - filter_file.call(file_reference) + file_reference.path == file_reference_change["path"] && file_filter.call(file_reference) end if file_references.length > 1 puts "Debug: Found more than one matching file with path " \ @@ -589,12 +601,13 @@ def find_file(project, file_reference_change, filter_file: ->(_) { true }) file_references.first end - def find_reference_proxy(project, container_item_proxy_change) + def find_reference_proxy(project, container_item_proxy_change, reference_filter: ->(_) { true }) reference_proxies = project.root_object.project_references.map do |project_ref_and_products| project_ref_and_products[:product_group].children.find do |product| product.remote_ref.remote_global_id_string == container_item_proxy_change["remoteGlobalIDString"] && - product.remote_ref.remote_info == container_item_proxy_change["remoteInfo"] + product.remote_ref.remote_info == container_item_proxy_change["remoteInfo"] && + reference_filter.call(product) end end.compact diff --git a/spec/kintsugi_apply_change_to_project_spec.rb b/spec/kintsugi_apply_change_to_project_spec.rb index f9faebf..f38b4c9 100644 --- a/spec/kintsugi_apply_change_to_project_spec.rb +++ b/spec/kintsugi_apply_change_to_project_spec.rb @@ -449,6 +449,30 @@ expect(base_project).to be_equivalent_to_project(theirs_project, ignore_keys: ["containerPortal"]) end + it "adds build file to a file reference that already exist" do + file_reference = base_project.main_group.new_reference("bar") + base_project.targets[0].frameworks_build_phase.add_file_reference(file_reference) + + base_project.main_group.new_reference("bar") + + base_project.save + + theirs_project = create_copy_of_project(base_project.path, "theirs") + + theirs_file_reference = theirs_project.main_group.files.find do |file| + !file.referrers.find { |referrer| referrer.is_a?(Xcodeproj::Project::PBXBuildFile) } && + file.display_name == "bar" + end + theirs_project.targets[0].frameworks_build_phase.add_file_reference(theirs_file_reference) + + changes_to_apply = get_diff(theirs_project, base_project) + + described_class.apply_change_to_project(base_project, changes_to_apply) + base_project.save + + expect(base_project).to be_equivalent_to_project(theirs_project) + end + it "adds file reference to build file" do file_reference = base_project.main_group.new_reference("bar")