Skip to content

Commit

Permalink
Kintsugi: Fix adding build file to a file with multiple references.
Browse files Browse the repository at this point in the history
Previously, if two file references that refer to the same file existed,
a build file's reference won't prefer one over the other. Even though it
is legal, a 1:1 relationship between build file and file reference
usually exist. Therefore the logic of adding a build file changes to
prefer a file reference that has no build files.
  • Loading branch information
byohay committed Oct 26, 2021
1 parent c7ca3a5 commit 0c6c1df
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 8 deletions.
29 changes: 21 additions & 8 deletions lib/kintsugi/apply_change_to_project.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 " \
Expand All @@ -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

Expand Down
24 changes: 24 additions & 0 deletions spec/kintsugi_apply_change_to_project_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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")

Expand Down

0 comments on commit 0c6c1df

Please sign in to comment.